DbOperation.scala 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. package utils
  2. import java.sql.Connection
  3. import java.util.concurrent._
  4. import play.api.db.DB
  5. import play.api.Play.current
  6. import play.core.NamedThreadFactory
  7. import scala.concurrent._
  8. import scala.concurrent.Future
  9. object DbOperation {
  10. // Common code between Anorm and Slick
  11. private val maxDbOperations = current.configuration.underlying.getInt("max-db-ops")
  12. private val partitionCount = current.configuration.getInt("db.default.partitionCount").getOrElse(2)
  13. private val maxConnections =
  14. partitionCount * current.configuration.getInt("db.default.maxConnectionsPerPartition").getOrElse(5)
  15. private val minConnections =
  16. partitionCount * current.configuration.getInt("db.default.minConnectionsPerPartition").getOrElse(5)
  17. private val tpe = new ThreadPoolExecutor(minConnections, maxConnections,
  18. 0L, TimeUnit.MILLISECONDS,
  19. new LinkedBlockingQueue[Runnable](), // TODO: Could use ArrayBlockingQueue?
  20. new NamedThreadFactory("dbEc"))
  21. private val dbEc = ExecutionContext.fromExecutorService(tpe)
  22. // Anorm code
  23. /**
  24. * Run a DB operation in the DB context. Automatically
  25. * provides a Session.
  26. */
  27. def asyncDbOp[T](op: Connection => T): Future[T] = {
  28. // If the thread-pool queue used by the database grows too large then our server
  29. // is probably struggling, and we should start dropping requests. If we don't
  30. // then we'll just slow everything down and it will fail anyway. Better to fail
  31. // quickly rather than slowly. Set the max size of our queue something above the
  32. // number of concurrent connections that we expect to be handling.
  33. if (tpe.getQueue.size > maxDbOperations) sys.error(s"Aborted DB operation because queue is > $maxDbOperations")
  34. Future {
  35. DB.withConnection { connection => op(connection) }
  36. }(dbEc)
  37. }
  38. }