Added support for changelog

This commit is contained in:
Šesták Vít
2016-03-09 09:55:00 +01:00
parent 4994a603b6
commit b1f04c3987
6 changed files with 139 additions and 8 deletions

View File

@@ -1,20 +1,34 @@
package services
import _root_.org.joda.time.DateTime
import com.google.inject.Inject
import com.mohiva.play.silhouette.api.LoginInfo
import com.ysoft.odc.SetDiff
import controllers.{ProjectsWithReports, ReportInfo}
import models._
import play.api.db.slick.{HasDatabaseConfigProvider, DatabaseConfigProvider}
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
import slick.jdbc.TransactionIsolation
import scala.collection.immutable.Iterable
import scala.concurrent.{Future, ExecutionContext}
import scala.concurrent.{ExecutionContext, Future}
final class SingleFutureExecutionThrottler() (implicit executionContext: ExecutionContext){
private var nextFuture: Future[_] = Future.successful(null)
def throttle[T](f: => Future[T]): Future[T] = synchronized{
val newFuture = nextFuture.recover{ case _ => null}.flatMap(_ => f)
nextFuture = newFuture
newFuture
}
}
final class NoThrottler() (implicit executionContext: ExecutionContext){
def throttle[T](f: => Future[T]): Future[T] = f
}
class VulnerabilityNotificationService @Inject() (protected val dbConfigProvider: DatabaseConfigProvider)(implicit executionContext: ExecutionContext) extends HasDatabaseConfigProvider[models.profile.type]{
import dbConfig.driver.api._
import models.tables
import models.tables.vulnerabilitySubscriptions
import models.tables._
def watchedProjectsByUser(identity: LoginInfo) = db.run(vulnerabilitySubscriptions.filter(_.user === identity).result)
def subscribe(user: LoginInfo, project: String) = db.run(vulnerabilitySubscriptions += VulnerabilitySubscription(user = user, project = project))
@@ -61,8 +75,33 @@ class VulnerabilityNotificationService @Inject() (protected val dbConfigProvider
}
/**
* The changelogThrottler is a temporary hack than prevents some congestion that seems to occur in HikariCP or maybe in Slick.
* It prevents exceptions like “java.sql.SQLException: Timeout of 1001ms encountered waiting for connection”.
* It is probably prevented at a wrong level, but it works :)
*/
private val changelogThrottler = new SingleFutureExecutionThrottler()
// private val changelogThrottler = new NoThrottler()
def changeAffectedProjects(vulnerabilityName: String, affectedProjectsDiff: SetDiff[String]): Future[Unit] = {
val time = DateTime.now()
def createRecord(projectName: String, direction: Change.Direction) = Change(time, vulnerabilityName, projectName, direction)
val recordsToAdd = affectedProjectsDiff.added.map(projectName => createRecord(projectName, Change.Direction.Added)) ++
affectedProjectsDiff.removed.map(projectName => createRecord(projectName, Change.Direction.Removed))
/*
Transaction:
It is essential to ensure that records in changelog appear in order. Low level of isolation might be even worse than running outside of transaction.
In longer term, it should be wrapped with transaction *with a proper isolation level* together with the export status modification.
*/
changelogThrottler.throttle(db.run(
(changelog.map(_.base) ++= recordsToAdd).withTransactionIsolation(TransactionIsolation.Serializable)
).map(_ => ()))
}
val issueTrackerExport = new ExportPlatform(tables.issueTrackerExportTables)
val mailExport = new ExportPlatform(tables.mailExportTables)
val diffDbExport = new ExportPlatform(tables.diffDbExportTables)
}