123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- package controllers
- import play.api.Play.current
- import play.api.db.DB
- import play.api.mvc._
- import play.api.libs.json.Json
- import java.util.concurrent._
- import scala.concurrent._
- import models.{World, Fortune}
- import utils._
- import scala.concurrent.Future
- import play.api.libs.concurrent.Execution.Implicits._
- import play.core.NamedThreadFactory
- object Application extends Controller {
- private val TestDatabaseRows = 10000
- private val partitionCount = current.configuration.getInt("db.default.partitionCount").getOrElse(2)
- private val maxConnections =
- partitionCount * current.configuration.getInt("db.default.maxConnectionsPerPartition").getOrElse(5)
- private val minConnections =
- partitionCount * current.configuration.getInt("db.default.minConnectionsPerPartition").getOrElse(5)
- private val tpe = new ThreadPoolExecutor(minConnections, maxConnections,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue[Runnable](),
- new NamedThreadFactory("dbEc"))
- private val dbEc = ExecutionContext.fromExecutorService(tpe)
- // If the thread-pool used by the database grows too large then our server
- // is probably struggling, and we should start dropping requests. Set
- // the max size of our queue something above the number of concurrent
- // connections that we need to handle.
- def isDbQueueTooBig: Boolean = tpe.getQueue.size() <= 1024
- def db = PredicatedAction(isDbQueueTooBig, ServiceUnavailable) {
- Action.async {
- getRandomWorlds(1).map { worlds =>
- Ok(Json.toJson(worlds.head))
- }
- }
- }
- def queries(countString: String) = PredicatedAction(isDbQueueTooBig, ServiceUnavailable) {
- Action.async {
- val n = parseCount(countString)
- getRandomWorlds(n).map { worlds =>
- Ok(Json.toJson(worlds))
- }
- }
- }
- private def parseCount(s: String): Int = {
- try {
- val parsed = java.lang.Integer.parseInt(s, 10)
- parsed match {
- case i if i < 1 => 1
- case i if i > 500 => 500
- case i => i
- }
- } catch {
- case _: NumberFormatException => 1
- }
- }
- private def getRandomWorlds(n: Int): Future[Seq[World]] = Future {
- val random = ThreadLocalRandom.current()
- DB.withConnection { implicit connection =>
- for (_ <- 1 to n) yield {
- val randomId: Long = random.nextInt(TestDatabaseRows) + 1
- World.findById(randomId)
- }
- }
- }(dbEc)
- def fortunes() = PredicatedAction(isDbQueueTooBig, ServiceUnavailable) {
- Action.async {
- Future {
- val fortunes = Fortune.getAll()
- val extendedFortunes = Fortune(0.toLong, "Additional fortune added at request time.") +: fortunes
- Ok(views.html.fortune(extendedFortunes))
- }
- }
- }
- def update(countString: String) = PredicatedAction(isDbQueueTooBig, ServiceUnavailable) {
- Action.async {
- val n = parseCount(countString)
- Future {
- val random = ThreadLocalRandom.current()
- val worlds = DB.withConnection { implicit connection =>
- for(_ <- 1 to n) yield {
- val randomId: Long = random.nextInt(TestDatabaseRows) + 1
- val world = World.findById(random.nextInt(TestDatabaseRows) + 1)
- val updatedWorld = world.copy(randomNumber = random.nextInt(10000) + 1)
- World.updateRandom(updatedWorld)
- updatedWorld
- }
- }
- Ok(Json.toJson(worlds)).withHeaders("Server" -> "Netty")
- }(dbEc)
- }
- }
- }
|