12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 |
- package utils
- import java.sql.Connection
- import java.util.concurrent._
- import javax.inject.{Singleton, Inject}
- import play.api.db.Database
- import play.api.Configuration
- import play.core.NamedThreadFactory
- import play.db.NamedDatabase
- import scala.concurrent._
- import scala.concurrent.Future
- @Singleton
- class DbOperation @Inject() (@NamedDatabase("hello_world") protected val db: Database,
- configuration: Configuration) {
- private val maxDbOperations = configuration.underlying.getInt("max-db-ops")
- private val partitionCount = configuration.getInt("db.hello_world.partitionCount").getOrElse(2)
- private val maxConnections =
- partitionCount * configuration.getInt("db.hello_world.maxConnectionsPerPartition").getOrElse(5)
- private val minConnections =
- partitionCount * configuration.getInt("db.hello_world.minConnectionsPerPartition").getOrElse(5)
- private val tpe = new ThreadPoolExecutor(minConnections, maxConnections,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue[Runnable](), // TODO: Could use ArrayBlockingQueue?
- new NamedThreadFactory("dbEc"))
- private val dbEc = ExecutionContext.fromExecutorService(tpe)
- // Anorm code
- /**
- * Run a DB operation in the DB context. Automatically
- * provides a Session.
- */
- def asyncDbOp[T](op: Connection => T): Future[T] = {
- // If the thread-pool queue used by the database grows too large then our server
- // is probably struggling, and we should start dropping requests. If we don't
- // then we'll just slow everything down and it will fail anyway. Better to fail
- // quickly rather than slowly. Set the max size of our queue something above the
- // number of concurrent connections that we expect to be handling.
- if (tpe.getQueue.size > maxDbOperations) sys.error(s"Aborted DB operation because queue is > $maxDbOperations")
- Future {
- db.withConnection { connection => op(connection) }
- }(dbEc)
- }
- }
|