Browse Source

Improve akka-http code (#2776)

* akka-http: Upgrade to latest versions

sbt 0.13.15
scala 2.12.2
akka 2.5.1
akka-http 10.0.6
scalate 1.8.0
scalatest 3.0.3

* akka-http: Better akka settings

* akka-http: Go from weird dependency injection format to slightly less weird standard cake-pattern

The cake pattern has its own flaws, but in such a simple App it works good
enough.

* akka-http: Auto format code with scalariform

* akka-http: Use idiomatic json marshalling

* akka-http: Enable pipelining

* akka-http: Update source code file

* akka-http: Configure db host through regular hocon features

* akka-http: Further clean up DB handling and route creation

* akka-http: Quiet down warning from travis that we are generating a longer content type than necessary

* akka-http: fix random number generation to provide only legal ids
Johannes Rudolph 8 years ago
parent
commit
625a7c0ca1
26 changed files with 274 additions and 457 deletions
  1. 9 5
      frameworks/Scala/akka-http/build.sbt
  2. 27 0
      frameworks/Scala/akka-http/project/Formatting.scala
  3. 0 1
      frameworks/Scala/akka-http/project/assembly.sbt
  4. 1 1
      frameworks/Scala/akka-http/project/build.properties
  5. 2 0
      frameworks/Scala/akka-http/project/plugins.sbt
  6. 1 4
      frameworks/Scala/akka-http/setup.sh
  7. 11 9
      frameworks/Scala/akka-http/source_code
  8. 9 3
      frameworks/Scala/akka-http/src/main/resources/application.conf
  9. 27 0
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/App.scala
  10. 7 16
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Bootstrap.scala
  11. 0 30
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Components.scala
  12. 14 0
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Infrastructure.scala
  13. 2 3
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Main.scala
  14. 3 20
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/RequestMapping.scala
  15. 7 0
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Templating.scala
  16. 6 5
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore/DataStore.scala
  17. 42 76
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore/MySqlDataStore.scala
  18. 7 0
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/entity/World.scala
  19. 8 48
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/DbHandler.scala
  20. 9 23
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/FortunesHandler.scala
  21. 15 27
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/JsonHandler.scala
  22. 17 12
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/PlaintextHandler.scala
  23. 22 71
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/QueriesHandler.scala
  24. 24 65
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/UpdatesHandler.scala
  25. 4 6
      frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/util/RandomGenerator.scala
  26. 0 32
      frameworks/Scala/akka-http/src/test/scala/com/typesafe/akka/http/benchmark/DbHandlerSpec.scala

+ 9 - 5
frameworks/Scala/akka-http/build.sbt

@@ -1,20 +1,24 @@
+val akkaV = "2.5.1"
+val akkaHttpV = "10.0.6"
+
 organization := "com.typesafe.akka"
 organization := "com.typesafe.akka"
 
 
 name := "akka-http-benchmark"
 name := "akka-http-benchmark"
 
 
 version := "0.0.1-SNAPSHOT"
 version := "0.0.1-SNAPSHOT"
 
 
-scalaVersion := "2.11.8"
+scalaVersion := "2.12.2"
 
 
 resolvers += "Akka Snapshot Repository" at "http://repo.akka.io/snapshots/"
 resolvers += "Akka Snapshot Repository" at "http://repo.akka.io/snapshots/"
 
 
 libraryDependencies ++= Seq(
 libraryDependencies ++= Seq(
-  "com.typesafe.akka" %% "akka-http" % "10.0.6",
-  "com.typesafe.akka" %% "akka-http-spray-json" % "10.0.6",
+  "com.typesafe.akka" %% "akka-http" % akkaHttpV,
+  "com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpV,
+  "com.typesafe.akka" %% "akka-stream" % akkaV,
   "mysql" % "mysql-connector-java" % "5.1.38",
   "mysql" % "mysql-connector-java" % "5.1.38",
   "com.zaxxer" % "HikariCP" % "2.5.1",
   "com.zaxxer" % "HikariCP" % "2.5.1",
-  "org.scalatra.scalate" %% "scalate-core" % "1.7.0",
-  "org.scalatest" %% "scalatest" % "2.2.4" % "test"
+  "org.scalatra.scalate" %% "scalate-core" % "1.8.0",
+  "org.scalatest" %% "scalatest" % "3.0.3" % "test"
 )
 )
 
 
 assemblyJarName in assembly := "akka-http-benchmark.jar"
 assemblyJarName in assembly := "akka-http-benchmark.jar"

+ 27 - 0
frameworks/Scala/akka-http/project/Formatting.scala

@@ -0,0 +1,27 @@
+import sbt._
+
+import com.typesafe.sbt.SbtScalariform
+import com.typesafe.sbt.SbtScalariform.ScalariformKeys
+
+object Formatting extends AutoPlugin {
+  override def trigger: PluginTrigger = AllRequirements
+  override def requires: Plugins = SbtScalariform
+
+  override def projectSettings: Seq[_root_.sbt.Def.Setting[_]] = formatSettings
+
+  lazy val formatSettings = SbtScalariform.scalariformSettings ++ Seq(
+    ScalariformKeys.preferences in Compile := formattingPreferences,
+    ScalariformKeys.preferences in Test := formattingPreferences
+  )
+
+  import scalariform.formatter.preferences._
+
+  def formattingPreferences =
+    FormattingPreferences()
+      .setPreference(RewriteArrowSymbols, false)
+      .setPreference(AlignParameters, true)
+      .setPreference(AlignSingleLineCaseStatements, true)
+      .setPreference(DanglingCloseParenthesis, Preserve)
+      .setPreference(DoubleIndentClassDeclaration, true)
+      .setPreference(SpacesAroundMultiImports, true)
+}

+ 0 - 1
frameworks/Scala/akka-http/project/assembly.sbt

@@ -1 +0,0 @@
-addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.4")

+ 1 - 1
frameworks/Scala/akka-http/project/build.properties

@@ -1 +1 @@
-sbt.version=0.13.15
+sbt.version=0.13.15

+ 2 - 0
frameworks/Scala/akka-http/project/plugins.sbt

@@ -0,0 +1,2 @@
+addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.6.0")
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.4")

+ 1 - 4
frameworks/Scala/akka-http/setup.sh

@@ -2,9 +2,6 @@
 
 
 fw_depends mysql java sbt
 fw_depends mysql java sbt
 
 
-sed -i 's|dbhost: "0.0.0.0"|dbhost: "'${DBHOST}'"|g' src/main/resources/application.conf
-sed -i 's|0.0.0.0:3306|'${DBHOST}':3306|g' src/main/resources/application.conf
-
 sbt 'assembly' -batch
 sbt 'assembly' -batch
 
 
-java -server -jar target/scala-2.11/akka-http-benchmark.jar &
+java -server -Dakka.http.benchmark.mysql.dbhost=$DBHOST -jar target/scala-2.12/akka-http-benchmark.jar &

+ 11 - 9
frameworks/Scala/akka-http/source_code

@@ -1,8 +1,8 @@
 ./akka-http/src/main
 ./akka-http/src/main
 ./akka-http/src/main/resources
 ./akka-http/src/main/resources
-./akka-http/src/main/resources/application.conf
 ./akka-http/src/main/resources/templates
 ./akka-http/src/main/resources/templates
 ./akka-http/src/main/resources/templates/fortunes.mustache
 ./akka-http/src/main/resources/templates/fortunes.mustache
+./akka-http/src/main/resources/application.conf
 ./akka-http/src/main/scala
 ./akka-http/src/main/scala
 ./akka-http/src/main/scala/com
 ./akka-http/src/main/scala/com
 ./akka-http/src/main/scala/com/typesafe
 ./akka-http/src/main/scala/com/typesafe
@@ -10,21 +10,23 @@
 ./akka-http/src/main/scala/com/typesafe/akka/http
 ./akka-http/src/main/scala/com/typesafe/akka/http
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Bootstrap.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Bootstrap.scala
-./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Components.scala
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Templating.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore/DataStore.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore/DataStore.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore/MySqlDataStore.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore/MySqlDataStore.scala
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/RequestMapping.scala
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/App.scala
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Main.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/entity
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/entity
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/entity/Fortune.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/entity/Fortune.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/entity/World.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/entity/World.scala
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/util
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/util/RandomGenerator.scala
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Infrastructure.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/DbHandler.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/DbHandler.scala
-./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/FortunesHandler.scala
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/UpdatesHandler.scala
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/QueriesHandler.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/JsonHandler.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/JsonHandler.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/PlaintextHandler.scala
 ./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/PlaintextHandler.scala
-./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/QueriesHandler.scala
-./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/UpdatesHandler.scala
-./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Main.scala
-./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/RequestMapping.scala
-./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/util
-./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/util/RandomGenerator.scala
+./akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/FortunesHandler.scala

+ 9 - 3
frameworks/Scala/akka-http/src/main/resources/application.conf

@@ -1,7 +1,12 @@
 akka {
 akka {
   actor {
   actor {
     default-dispatcher {
     default-dispatcher {
-      throughput = 50
+      fork-join-executor {
+        parallelism-min = 1    # don't constrain parallelism statically
+        parallelism-max = 64   # --
+
+        parallelism-factor = 1 # one thread per core is enough
+      }
     }
     }
   }
   }
   http {
   http {
@@ -9,10 +14,11 @@ akka {
       host: 0.0.0.0
       host: 0.0.0.0
       port: 9000
       port: 9000
       mysql {
       mysql {
-        dbhost: "0.0.0.0"
+        dbhost: 0.0.0.0
+        dbport: 3306
         dbuser: "benchmarkdbuser"
         dbuser: "benchmarkdbuser"
         dbpass: "benchmarkdbpass"
         dbpass: "benchmarkdbpass"
-        jdbc-url: "jdbc:mysql://0.0.0.0:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+        jdbc-url: "jdbc:mysql://"${akka.http.benchmark.mysql.dbhost}":"${akka.http.benchmark.mysql.dbport}"/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
         connection-pool-size: 100
         connection-pool-size: 100
         thread-pool-size: 100
         thread-pool-size: 100
       }
       }

+ 27 - 0
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/App.scala

@@ -0,0 +1,27 @@
+package com.typesafe.akka.http.benchmark
+
+import akka.actor.ActorSystem
+import akka.stream.ActorMaterializer
+import akka.stream.Materializer
+import com.typesafe.akka.http.benchmark.datastore.MySqlDataStore
+import com.typesafe.akka.http.benchmark.handlers._
+import com.typesafe.akka.http.benchmark.util.RandomGenerator
+import com.typesafe.config.Config
+import com.typesafe.config.ConfigFactory
+import org.fusesource.scalate.Binding
+import org.fusesource.scalate.TemplateEngine
+
+import scala.concurrent.ExecutionContext
+
+class App extends Infrastructure with RandomGenerator with MySqlDataStore with PlaintextHandler with JsonHandler with DbHandler with QueriesHandler with FortunesHandler with UpdatesHandler with RequestMapping with BenchmarkBootstrap with Templating {
+  lazy val templateEngine = new TemplateEngine()
+
+  implicit lazy val system: ActorSystem = ActorSystem("akka-http-benchmark")
+  lazy val executionContext: ExecutionContext = system.dispatcher
+  lazy val materializer: Materializer = ActorMaterializer()
+  lazy val appConfig: Config = ConfigFactory.load
+
+  def layout(uri: String, attributes: Map[String, Any], extraBindings: Traversable[Binding]): String =
+    templateEngine.layout(uri, attributes, extraBindings)
+}
+

+ 7 - 16
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Bootstrap.scala

@@ -1,29 +1,20 @@
 package com.typesafe.akka.http.benchmark
 package com.typesafe.akka.http.benchmark
 
 
-import akka.actor.ActorSystem
 import akka.http.scaladsl.Http
 import akka.http.scaladsl.Http
 import akka.http.scaladsl.server.Route
 import akka.http.scaladsl.server.Route
-import akka.stream.ActorMaterializer
-import com.typesafe.config.Config
 
 
 trait Bootstrap {
 trait Bootstrap {
   def run(): Unit
   def run(): Unit
 }
 }
 
 
-class BenchmarkBootstrap(components: {
-  val config: Config
-  val system: ActorSystem
-  val route: Route
-}) extends Bootstrap {
-  implicit val system = components.system
-  val config = components.config
-
-  import system.dispatcher
-
+trait BenchmarkBootstrap extends Bootstrap { _: Infrastructure with RequestMapping =>
   override def run(): Unit = {
   override def run(): Unit = {
+    val routeHandler = Route.asyncHandler(asRoute)
 
 
-    implicit val system = ActorSystem()
-    implicit val materializer = ActorMaterializer()
-    Http().bindAndHandle(components.route, config.getString("akka.http.benchmark.host"), config.getInt("akka.http.benchmark.port"))
+    Http().bindAndHandleAsync(
+      routeHandler,
+      appConfig.getString("akka.http.benchmark.host"),
+      appConfig.getInt("akka.http.benchmark.port"),
+      parallelism = 16)
   }
   }
 }
 }

+ 0 - 30
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Components.scala

@@ -1,30 +0,0 @@
-package com.typesafe.akka.http.benchmark
-
-import akka.actor.ActorSystem
-import akka.http.scaladsl.server.Route
-import com.typesafe.akka.http.benchmark.datastore.{DataStore, MySqlDataStore}
-import com.typesafe.akka.http.benchmark.handlers._
-import com.typesafe.akka.http.benchmark.util.RandomGenerator
-import com.typesafe.config.{Config, ConfigFactory}
-import org.fusesource.scalate.TemplateEngine
-
-import scala.concurrent.ExecutionContext
-
-trait Components {
-  implicit val system = ActorSystem("akka-http-benchmark")
-  implicit val executionContext: ExecutionContext = system.dispatcher
-  lazy val config: Config = ConfigFactory.load
-  lazy val randomGenerator = new RandomGenerator(this)
-  lazy val dataStore: DataStore = new MySqlDataStore(this)
-  lazy val plaintextHandler = new PlaintextHandler(this)
-  lazy val jsonHandler = new JsonHandler(this)
-  lazy val dbHandler = new DbHandler(this)
-  lazy val queriesHandler = new QueriesHandler(this)
-  lazy val fortunesHandler = new FortunesHandler(this)
-  lazy val updatesHandler = new UpdatesHandler(this)
-  lazy val route: Route = new RequestMapping(this).asRoute
-  lazy val bootstrap: Bootstrap = new BenchmarkBootstrap(this)
-  lazy val templateEngine: TemplateEngine = new TemplateEngine
-}
-
-object Components extends Components

+ 14 - 0
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Infrastructure.scala

@@ -0,0 +1,14 @@
+package com.typesafe.akka.http.benchmark
+
+import akka.actor.ActorSystem
+import akka.stream.Materializer
+import com.typesafe.config.Config
+
+import scala.concurrent.ExecutionContext
+
+trait Infrastructure {
+  implicit def system: ActorSystem
+  implicit def executionContext: ExecutionContext
+  implicit def materializer: Materializer
+  def appConfig: Config
+}

+ 2 - 3
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Main.scala

@@ -1,7 +1,6 @@
 package com.typesafe.akka.http.benchmark
 package com.typesafe.akka.http.benchmark
 
 
 object Main {
 object Main {
-  def main(args: Array[String]): Unit = {
-    Components.bootstrap.run()
-  }
+  def main(args: Array[String]): Unit =
+    (new App).run()
 }
 }

+ 3 - 20
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/RequestMapping.scala

@@ -5,24 +5,7 @@ import akka.http.scaladsl.server.Directives._
 import akka.http.scaladsl.server.Route
 import akka.http.scaladsl.server.Route
 import com.typesafe.akka.http.benchmark.handlers._
 import com.typesafe.akka.http.benchmark.handlers._
 
 
-class RequestMapping(components: {
-  val plaintextHandler: PlaintextHandler
-  val jsonHandler: JsonHandler
-  val dbHandler: DbHandler
-  val queriesHandler: QueriesHandler
-  val fortunesHandler: FortunesHandler
-  val updatesHandler: UpdatesHandler
-}) {
-  val plaintext = components.plaintextHandler.endpoint
-  val json = components.jsonHandler.endpoint
-  val db = components.dbHandler.endpoint
-  val queries = components.queriesHandler.endpoint
-  val fortunes = components.fortunesHandler.endpoint
-  val updates = components.updatesHandler.endpoint
-
-  def asRoute: Route = {
-    respondWithHeader(Connection("Keep-Alive")) {
-       plaintext ~ json ~ db ~ queries ~ fortunes ~ updates
-    }
-  }
+trait RequestMapping { _: PlaintextHandler with JsonHandler with DbHandler with QueriesHandler with FortunesHandler with UpdatesHandler =>
+  def asRoute: Route =
+    plainTextEndpoint ~ jsonEndpoint ~ dbEndpoint ~ queriesEndpoint ~ fortunesEndpoint ~ updatesEndpoint
 }
 }

+ 7 - 0
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/Templating.scala

@@ -0,0 +1,7 @@
+package com.typesafe.akka.http.benchmark
+
+import org.fusesource.scalate.Binding
+
+trait Templating {
+  def layout(uri: String, attributes: Map[String, Any] = Map(), extraBindings: Traversable[Binding] = Nil): String
+}

+ 6 - 5
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore/DataStore.scala

@@ -1,13 +1,14 @@
 package com.typesafe.akka.http.benchmark.datastore
 package com.typesafe.akka.http.benchmark.datastore
 
 
-import com.typesafe.akka.http.benchmark.entity.{Fortune, World}
+import scala.collection.immutable
+import com.typesafe.akka.http.benchmark.entity.{ Fortune, World }
 
 
 import scala.concurrent.Future
 import scala.concurrent.Future
 
 
 trait DataStore {
 trait DataStore {
-  def findOne(id: Int): Future[World]
+  def findWorldById(id: Int): Future[Option[World]]
+  def requireWorldById(id: Int): Future[World]
+  def updateWorld(world: World): Future[Boolean]
 
 
-  def updateOne(id: Int, randomNumber: Int): Future[Boolean]
-
-  def getFortunes: Future[List[Fortune]]
+  def getFortunes: Future[immutable.Seq[Fortune]]
 }
 }

+ 42 - 76
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/datastore/MySqlDataStore.scala

@@ -1,106 +1,72 @@
 package com.typesafe.akka.http.benchmark.datastore
 package com.typesafe.akka.http.benchmark.datastore
 
 
+import java.sql.PreparedStatement
 import java.sql.ResultSet
 import java.sql.ResultSet
-import java.util.Properties
 import java.util.concurrent.Executors
 import java.util.concurrent.Executors
 
 
-import akka.actor.ActorSystem
-import com.typesafe.akka.http.benchmark.entity.{Fortune, World}
-import com.typesafe.config.Config
+import com.typesafe.akka.http.benchmark.Infrastructure
+import com.typesafe.akka.http.benchmark.entity.Fortune
+import com.typesafe.akka.http.benchmark.entity.World
 import com.zaxxer.hikari._
 import com.zaxxer.hikari._
-import scala.concurrent.{ExecutionContext, Future, Promise}
 
 
-class MySqlDataStore(components: {
-  val system: ActorSystem
-  val config: Config
-}) extends DataStore {
-  val config = components.config.getConfig("akka.http.benchmark.mysql")
+import scala.collection.immutable
+import scala.concurrent.ExecutionContext
+import scala.concurrent.Future
 
 
-  private val dataSource = new HikariDataSource {
+// TODO: use slick or similar here instead for more idiomatic usage
+trait MySqlDataStore extends DataStore { _: Infrastructure =>
+  lazy val config = appConfig.getConfig("akka.http.benchmark.mysql")
+
+  private lazy val dataSource = new HikariDataSource {
     setJdbcUrl(config.getString("jdbc-url"))
     setJdbcUrl(config.getString("jdbc-url"))
     setUsername(config.getString("dbuser"))
     setUsername(config.getString("dbuser"))
     setPassword(config.getString("dbpass"))
     setPassword(config.getString("dbpass"))
     setMaximumPoolSize(config.getInt("connection-pool-size"))
     setMaximumPoolSize(config.getInt("connection-pool-size"))
   }
   }
 
 
-  private implicit val executionContext: ExecutionContext = {
+  private implicit lazy val dbExecutionContext: ExecutionContext = {
     val size = config.getInt("thread-pool-size")
     val size = config.getInt("thread-pool-size")
     val threadPool = Executors.newFixedThreadPool(size)
     val threadPool = Executors.newFixedThreadPool(size)
-    new ExecutionContext {
-      override def reportFailure(cause: Throwable): Unit = {
-        components.system.log.error(cause, "exception in mysql thread pool")
-      }
+    ExecutionContext.fromExecutor(threadPool)
+  }
 
 
-      override def execute(runnable: Runnable): Unit = {
-        threadPool.execute(runnable)
-      }
+  def requireWorldById(id: Int): Future[World] = findWorldById(id).map(_.getOrElse(throw new RuntimeException(s"Element with id $id was not found.")))(executionContext)
+  override def findWorldById(id: Int): Future[Option[World]] =
+    withStatement("select id, randomNumber from World where id = ?") { stmt =>
+      stmt.setInt(1, id)
+      val rs = stmt.executeQuery()
+
+      if (rs.next()) Some(World(rs.getInt("id"), rs.getInt("randomNumber")))
+      else None
     }
     }
-  }
 
 
-  override def findOne(id: Int): Future[World] = {
-    val select = "select id, randomNumber from World where id = ?"
-    val promise = Promise[World]()
-    executionContext.execute(new Runnable {
-      override def run(): Unit = {
-        val conn = dataSource.getConnection
-        val stmt = conn.prepareStatement(select)
-        stmt.setInt(1, id)
-        val rs = stmt.executeQuery()
-        val world = rs.next() match {
-          case true =>
-            World(rs.getInt("id"), rs.getInt("randomNumber"))
-        }
-        rs.close()
-        stmt.close()
-        conn.close()
-        promise.success(world)
-      }
-    })
-    promise.future
-  }
+  override def updateWorld(world: World): Future[Boolean] =
+    withStatement("update World set randomNumber = ? where id = ?") { stmt =>
+      stmt.setInt(1, world.randomNumber)
+      stmt.setInt(2, world.id)
+      stmt.executeUpdate() > 0
+    }
 
 
-  override def updateOne(id: Int, randomNumber: Int): Future[Boolean] = {
-    val update = "update World set randomNumber = ? where id = ?"
-    val promise = Promise[Boolean]()
-    executionContext.execute(new Runnable {
-      override def run(): Unit = {
-        val conn = dataSource.getConnection
-        val stmt = conn.prepareStatement(update)
-        stmt.setInt(1, randomNumber)
-        stmt.setInt(2, id)
-        val n = stmt.executeUpdate()
-        stmt.close()
-        conn.close()
-        promise.success(n > 0)
-      }
-    })
-    promise.future
-  }
+  override def getFortunes: Future[immutable.Seq[Fortune]] =
+    withStatement("select id, message from Fortune") { stmt =>
+      val rs = stmt.executeQuery()
+      (Fortune(0, "Additional fortune added at request time.") +: rs.map(r => Fortune(r.getInt("id"), r.getString("message"))).toVector)
+        .sortBy(_.message)
+    }
 
 
-  override def getFortunes: Future[List[Fortune]] = {
-    val select = "select id, message from Fortune"
-    val promise = Promise[List[Fortune]]()
-    executionContext.execute(new Runnable {
-      override def run(): Unit = {
-        val conn = dataSource.getConnection
-        val stmt = conn.prepareStatement(select)
-        val rs = stmt.executeQuery()
-        val fortunes = {
-          rs.map(r => Fortune(r.getInt("id"), r.getString("message"))).toList :+ Fortune(0, "Additional fortune added at request time.")
-        }.sortBy(_.message)
-        rs.close()
+  private def withStatement[T](statement: String)(f: PreparedStatement => T): Future[T] =
+    Future {
+      val conn = dataSource.getConnection
+      val stmt = conn.prepareStatement(statement)
+      try f(stmt)
+      finally {
         stmt.close()
         stmt.close()
         conn.close()
         conn.close()
-        promise.success(fortunes)
       }
       }
-    })
-    promise.future
-  }
+    }(dbExecutionContext)
 
 
   implicit class RsIterator(rs: ResultSet) extends Iterator[ResultSet] {
   implicit class RsIterator(rs: ResultSet) extends Iterator[ResultSet] {
     def hasNext: Boolean = rs.next()
     def hasNext: Boolean = rs.next()
-
     def next(): ResultSet = rs
     def next(): ResultSet = rs
   }
   }
-
 }
 }

+ 7 - 0
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/entity/World.scala

@@ -1,3 +1,10 @@
 package com.typesafe.akka.http.benchmark.entity
 package com.typesafe.akka.http.benchmark.entity
 
 
+import spray.json.DefaultJsonProtocol
+import spray.json.RootJsonFormat
+
 case class World(id: Int, randomNumber: Int)
 case class World(id: Int, randomNumber: Int)
+object World {
+  import DefaultJsonProtocol._
+  implicit val worldFormat: RootJsonFormat[World] = jsonFormat(World.apply, "id", "randomNumber")
+}

+ 8 - 48
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/DbHandler.scala

@@ -1,58 +1,18 @@
 package com.typesafe.akka.http.benchmark.handlers
 package com.typesafe.akka.http.benchmark.handlers
 
 
-import akka.http.scaladsl.model.HttpCharsets._
-import akka.http.scaladsl.model.MediaTypes._
-import akka.http.scaladsl.model.{HttpEntity, HttpResponse, StatusCodes}
 import akka.http.scaladsl.server.Directives._
 import akka.http.scaladsl.server.Directives._
+import com.typesafe.akka.http.benchmark.Infrastructure
 import com.typesafe.akka.http.benchmark.datastore.DataStore
 import com.typesafe.akka.http.benchmark.datastore.DataStore
-import com.typesafe.akka.http.benchmark.entity.World
 import com.typesafe.akka.http.benchmark.util.RandomGenerator
 import com.typesafe.akka.http.benchmark.util.RandomGenerator
-import spray.json.{DefaultJsonProtocol, RootJsonFormat}
 
 
-import scala.concurrent.ExecutionContext
-import scala.util.{Failure, Success}
+trait DbHandler { _: Infrastructure with DataStore with RandomGenerator =>
+  import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
 
 
-class DbHandler(components: {
-  val executionContext: ExecutionContext
-  val dataStore: DataStore
-  val randomGenerator: RandomGenerator
-}) {
-  val randomGenerator = components.randomGenerator
-  val dataStore = components.dataStore
-  implicit val ec = components.executionContext
-
-  import DbHandler.Protocols._
-
-  def endpoint = get {
-    path("db") {
-      onComplete(response) {
-        case Success(record) => complete(record)
-        case Failure(t) => failWith(t)
+  def dbEndpoint =
+    get {
+      path("db") {
+        val id = nextRandomIntBetween1And10000
+        complete(requireWorldById(id))
       }
       }
     }
     }
-  }
-
-  def response = {
-    val id = randomGenerator.next
-    dataStore.findOne(id).map {
-      record => HttpResponse(StatusCodes.OK, entity = HttpEntity(record.toResponse.toJson.toString()).withContentType(`application/json`))
-    }
-  }
-
-}
-
-object DbHandler {
-
-  object Protocols extends DefaultJsonProtocol {
-
-    case class Response(id: Int, randomNumber: Int)
-
-    implicit val responseFormat: RootJsonFormat[Response] = jsonFormat2(Response.apply)
-
-    implicit class ToResponse(record: World) {
-      def toResponse = Response(record.id, record.randomNumber)
-    }
-
-  }
-
 }
 }

+ 9 - 23
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/FortunesHandler.scala

@@ -1,42 +1,28 @@
 package com.typesafe.akka.http.benchmark.handlers
 package com.typesafe.akka.http.benchmark.handlers
 
 
-import akka.actor.ActorSystem
 import akka.http.scaladsl.model.HttpCharsets._
 import akka.http.scaladsl.model.HttpCharsets._
 import akka.http.scaladsl.model.MediaTypes._
 import akka.http.scaladsl.model.MediaTypes._
 import akka.http.scaladsl.model._
 import akka.http.scaladsl.model._
 import akka.http.scaladsl.server.Directives._
 import akka.http.scaladsl.server.Directives._
+import com.typesafe.akka.http.benchmark.Infrastructure
+import com.typesafe.akka.http.benchmark.Templating
 import com.typesafe.akka.http.benchmark.datastore.DataStore
 import com.typesafe.akka.http.benchmark.datastore.DataStore
-import org.fusesource.scalate.TemplateEngine
 
 
 import scala.concurrent.Future
 import scala.concurrent.Future
-import scala.util.{Failure, Success}
 
 
-class FortunesHandler(components: {
-  val system: ActorSystem
-  val dataStore: DataStore
-  val templateEngine: TemplateEngine
-}) {
-
-  import components.system.dispatcher
-
-  val dataStore = components.dataStore
-  val engine = components.templateEngine
-
-  def endpoint = get {
-    path("fortunes") {
-      onComplete(response) {
-        case Success(record) => complete(record)
-        case Failure(t) => failWith(t)
+trait FortunesHandler { _: Infrastructure with DataStore with Templating =>
+  def fortunesEndpoint =
+    get {
+      path("fortunes") {
+        complete(response)
       }
       }
     }
     }
-  }
 
 
   def response: Future[HttpResponse] = {
   def response: Future[HttpResponse] = {
-    dataStore.getFortunes.map {
+    getFortunes.map {
       fortunes =>
       fortunes =>
-        val body = engine.layout("/templates/fortunes.mustache", Map("fortunes" -> fortunes))
+        val body = layout("/templates/fortunes.mustache", Map("fortunes" -> fortunes))
         HttpResponse(StatusCodes.OK, entity = HttpEntity(body).withContentType(`text/html`.withCharset(`UTF-8`)))
         HttpResponse(StatusCodes.OK, entity = HttpEntity(body).withContentType(`text/html`.withCharset(`UTF-8`)))
     }
     }
-
   }
   }
 }
 }

+ 15 - 27
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/JsonHandler.scala

@@ -1,36 +1,24 @@
 package com.typesafe.akka.http.benchmark.handlers
 package com.typesafe.akka.http.benchmark.handlers
 
 
-import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
-import akka.http.scaladsl.model.HttpCharsets._
-import akka.http.scaladsl.model.MediaTypes._
-import akka.http.scaladsl.model._
 import akka.http.scaladsl.server.Directives._
 import akka.http.scaladsl.server.Directives._
-import spray.json.{DefaultJsonProtocol, RootJsonFormat}
+import spray.json.DefaultJsonProtocol
+import spray.json.RootJsonFormat
 
 
+case class JsonResponse(message: String)
+object JsonResponse {
+  import DefaultJsonProtocol._
+  implicit val responseFormat: RootJsonFormat[JsonResponse] = jsonFormat1(JsonResponse.apply)
+}
 
 
-class JsonHandler(components: {
-
-}) {
+trait JsonHandler {
+  import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
 
 
-  import JsonHandler.Protocols._
+  lazy val jsonResponse = JsonResponse("Hello, World!") // domain object
 
 
-  def endpoint = get {
-    path("json") {
-      complete(response)
+  def jsonEndpoint =
+    get {
+      path("json") {
+        complete(jsonResponse)
+      }
     }
     }
-  }
-
-  def response = Response("Hello, World!")
 }
 }
-
-object JsonHandler {
-
-  object Protocols extends DefaultJsonProtocol with SprayJsonSupport {
-
-    case class Response(message: String)
-
-    implicit val responseFormat: RootJsonFormat[Response] = jsonFormat1(Response.apply)
-
-  }
-
-}

+ 17 - 12
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/PlaintextHandler.scala

@@ -1,18 +1,23 @@
 package com.typesafe.akka.http.benchmark.handlers
 package com.typesafe.akka.http.benchmark.handlers
 
 
-import akka.http.scaladsl.model.HttpCharsets._
-import akka.http.scaladsl.model.MediaTypes._
-import akka.http.scaladsl.model.{HttpEntity, HttpResponse, StatusCodes}
+import akka.http.scaladsl.model.HttpCharsets
+import akka.http.scaladsl.model.HttpEntity
+import akka.http.scaladsl.model.HttpResponse
+import akka.http.scaladsl.model.MediaType
 import akka.http.scaladsl.server.Directives._
 import akka.http.scaladsl.server.Directives._
 
 
-class PlaintextHandler(components: {
-
-}) {
-  def endpoint = get {
-    path("plaintext") {
-      complete(response)
-    }
+trait PlaintextHandler {
+  lazy val plainTextResponse = {
+    // akka-http will always generate a charset parameter for text/plain, so to be competitive, we create a custom
+    // one here to save a few bytes of headers for this particular test case.
+    //
+    // This is explicitly allowed in
+    // http://frameworkbenchmarks.readthedocs.org/en/latest/Project-Information/Framework-Tests/#specific-test-requirements
+    val simpleTextPlainMediaType = MediaType.customWithFixedCharset("text", "plain", HttpCharsets.`UTF-8`)
+    HttpResponse(entity = HttpEntity(simpleTextPlainMediaType, "Hello, World!"))
   }
   }
-
-  def response = "Hello, World!"
+  def plainTextEndpoint =
+    (get & path("plaintext")) {
+        complete(plainTextResponse)
+    }
 }
 }

+ 22 - 71
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/QueriesHandler.scala

@@ -1,80 +1,31 @@
 package com.typesafe.akka.http.benchmark.handlers
 package com.typesafe.akka.http.benchmark.handlers
 
 
-import akka.actor.ActorSystem
-import akka.http.scaladsl.model.HttpCharsets._
-import akka.http.scaladsl.model.MediaTypes._
-import akka.http.scaladsl.model.{HttpEntity, HttpResponse, StatusCodes}
-import akka.http.scaladsl.server.Directives._
-import akka.http.scaladsl.server.directives.ParameterDirectives
+import com.typesafe.akka.http.benchmark.Infrastructure
 import com.typesafe.akka.http.benchmark.datastore.DataStore
 import com.typesafe.akka.http.benchmark.datastore.DataStore
-import com.typesafe.akka.http.benchmark.entity.World
-import com.typesafe.akka.http.benchmark.handlers.DbHandler.Protocols._
 import com.typesafe.akka.http.benchmark.util.RandomGenerator
 import com.typesafe.akka.http.benchmark.util.RandomGenerator
-import spray.json.{DefaultJsonProtocol, RootJsonFormat}
 
 
 import scala.concurrent.Future
 import scala.concurrent.Future
-import scala.util.control.Exception._
-import scala.util.{Failure, Success}
-
-class QueriesHandler(components: {
-  val dataStore: DataStore
-  val system: ActorSystem
-  val randomGenerator: RandomGenerator
-}) {
-  val dataStore = components.dataStore
-  val randomGenerator = components.randomGenerator
-
-  import ParameterDirectives._
-  import ParamDef._
-  import ParamMagnet._
-  import components.system.dispatcher
-
-
-  def endpoint = get {
-    path("queries") {
-      parameter('queries.?) { queries => onComplete(response(queries)) {
-        case Success(worlds) => complete(worlds)
-        case Failure(t) => failWith(t)
-      }
+import scala.util.Try
+
+trait QueriesHandler {
+  _: Infrastructure with DataStore with RandomGenerator =>
+  import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
+  import akka.http.scaladsl.server.Directives._
+  import spray.json.DefaultJsonProtocol._
+
+  def queriesEndpoint =
+    get {
+      path("queries") {
+        parameter('queries.?) { numQueries =>
+          // The queries parameter must be bounded to between 1 and 500. If the parameter is missing,
+          // is not an integer, or is an integer less than 1, the value should be interpreted as 1;
+          // if greater than 500, the value should be interpreted as 500.
+
+          val realNumQueries = Try(numQueries.getOrElse("1").toInt).getOrElse(1).min(500).max(1)
+          complete {
+            Future.traverse(Seq.fill(realNumQueries)(nextRandomIntBetween1And10000))(requireWorldById)
+          }
+        }
       }
       }
     }
     }
-  }
-
-  val catcher = catching(classOf[NumberFormatException]).withApply(t => 1)
-
-  def response(queries: Option[String]): Future[HttpResponse] = {
-
-    val range = queries.map(i => catcher {
-      i.toInt
-    }).getOrElse(1).min(500).max(1)
-    Future.sequence {
-      (0 until range).map {
-        _ => randomGenerator.next
-      }.map {
-        id => dataStore.findOne(id)
-      }
-    }.map {
-      worlds => HttpResponse(StatusCodes.OK, entity = HttpEntity(worlds.toList.map(_.toResponse).toJson.toString()).withContentType(`application/json`))
-    }
-
-  }
-
-}
-
-object QueriesHandler {
-
-  object Protocols extends DefaultJsonProtocol {
-
-    case class Response(id: Int, randomNumber: Int)
-
-    implicit val responseFormat: RootJsonFormat[Response] = jsonFormat2(Response.apply)
-
-    implicit val responseListFormat: RootJsonFormat[List[Response]] = listFormat[Response]
-
-    implicit class ToResponse(record: World) {
-      def toResponse = Response(record.id, record.randomNumber)
-    }
-
-  }
-
 }
 }

+ 24 - 65
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/handlers/UpdatesHandler.scala

@@ -1,76 +1,35 @@
 package com.typesafe.akka.http.benchmark.handlers
 package com.typesafe.akka.http.benchmark.handlers
 
 
-import akka.actor.ActorSystem
-import akka.http.scaladsl.model.HttpCharsets._
-import akka.http.scaladsl.model.MediaTypes._
-import akka.http.scaladsl.model.{HttpEntity, HttpResponse, StatusCodes}
 import akka.http.scaladsl.server.Directives._
 import akka.http.scaladsl.server.Directives._
+import com.typesafe.akka.http.benchmark.Infrastructure
 import com.typesafe.akka.http.benchmark.datastore.DataStore
 import com.typesafe.akka.http.benchmark.datastore.DataStore
 import com.typesafe.akka.http.benchmark.entity.World
 import com.typesafe.akka.http.benchmark.entity.World
 import com.typesafe.akka.http.benchmark.util.RandomGenerator
 import com.typesafe.akka.http.benchmark.util.RandomGenerator
-import spray.json.{DefaultJsonProtocol, RootJsonFormat}
 
 
 import scala.concurrent.Future
 import scala.concurrent.Future
-import scala.util.control.Exception._
-import scala.util.{Failure, Success}
-
-class UpdatesHandler(components: {
-  val dataStore: DataStore
-  val system: ActorSystem
-  val randomGenerator: RandomGenerator
-}) {
-  val dataStore = components.dataStore
-  val randomGenerator = components.randomGenerator
-
-  import UpdatesHandler.Protocols._
-  import components.system.dispatcher
-
-  def endpoint = get {
-    path("updates") {
-      parameter('queries.?) { queries => onComplete(response(queries)) {
-        case Success(worlds) => complete(worlds)
-        case Failure(t) => failWith(t)
-      }
+import scala.util.Try
+
+trait UpdatesHandler { _: Infrastructure with DataStore with RandomGenerator =>
+  import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
+  import spray.json.DefaultJsonProtocol._
+
+  def updatesEndpoint =
+    get {
+      path("updates") {
+        parameter('queries.?) { numQueries =>
+          val realNumQueries = Try(numQueries.getOrElse("1").toInt).getOrElse(1).min(500).max(1)
+
+          def mutateOne(id: Int): Future[World] =
+            for {
+              world <- requireWorldById(id)
+              newWorld = world.copy(randomNumber = nextRandomIntBetween1And10000)
+              wasUpdated <- updateWorld(newWorld)
+            } yield newWorld // ignore `wasUpdated`
+
+          complete {
+            Future.traverse(Seq.fill(realNumQueries)(nextRandomIntBetween1And10000))(mutateOne)
+          }
+        }
       }
       }
     }
     }
-  }
-
-  val catcher = catching(classOf[NumberFormatException]).withApply(t => 1)
-
-  def response(queries: Option[String]): Future[HttpResponse] = {
-    val range = queries.map(i => catcher {
-      i.toInt
-    }).getOrElse(1).min(500).max(1)
-    Future.sequence {
-      (0 until range).toList.map {
-        _ => randomGenerator.next
-      }.map {
-        id => dataStore.findOne(id)
-      }
-    }.map {
-      worlds => worlds.map(_.copy(randomNumber = randomGenerator.next))
-    }.flatMap {
-      worlds => Future.sequence(worlds.map(world => dataStore.updateOne(world.id, world.randomNumber).map(_ => world)))
-    }.map {
-      worlds => HttpResponse(StatusCodes.OK, entity = HttpEntity(worlds.map(_.toResponse).toJson.toString()).withContentType(`application/json`))
-    }
-  }
 }
 }
-
-object UpdatesHandler {
-
-  object Protocols extends DefaultJsonProtocol {
-
-    case class Response(id: Int, randomNumber: Int)
-
-    implicit val responseFormat: RootJsonFormat[Response] = jsonFormat2(Response.apply)
-
-    implicit val responseListFormat: RootJsonFormat[List[Response]] = listFormat[Response]
-
-    implicit class ToResponse(record: World) {
-      def toResponse = Response(record.id, record.randomNumber)
-    }
-
-  }
-
-}

+ 4 - 6
frameworks/Scala/akka-http/src/main/scala/com/typesafe/akka/http/benchmark/util/RandomGenerator.scala

@@ -1,10 +1,8 @@
 package com.typesafe.akka.http.benchmark.util
 package com.typesafe.akka.http.benchmark.util
 
 
-class RandomGenerator(components: {
+import java.util.concurrent.ThreadLocalRandom
 
 
-}) {
-
-  def next: Int = {
-    (Math.random() * 10000 + 1).toInt
-  }
+trait RandomGenerator {
+  def nextRandomIntBetween1And10000: Int =
+    ThreadLocalRandom.current().nextInt(10000) + 1
 }
 }

+ 0 - 32
frameworks/Scala/akka-http/src/test/scala/com/typesafe/akka/http/benchmark/DbHandlerSpec.scala

@@ -1,32 +0,0 @@
-package com.typesafe.akka.http.benchmark
-
-import akka.http.scaladsl.server.RequestContext
-import com.typesafe.akka.http.benchmark.datastore.DataStore
-import com.typesafe.akka.http.benchmark.entity.{Fortune, World}
-import com.typesafe.akka.http.benchmark.util.RandomGenerator
-import org.scalatest._
-
-import scala.concurrent.Future
-
-class DbHandlerSpec extends FlatSpec with Matchers {
-  val components = new Components {
-    self =>
-
-    import self.system.dispatcher
-
-    override lazy val randomGenerator: RandomGenerator = new RandomGenerator(self) {
-      override def next: Int = 1
-    }
-    override lazy val dataStore: DataStore = new DataStore {
-      override def findOne(id: Int): Future[World] = {
-        Future(World(1, 1))
-      }
-
-      override def updateOne(id: Int, randomNumber: Int): Future[Boolean] = Future(true)
-
-      override def getFortunes: Future[List[Fortune]] = Future(List(Fortune(0, "Additional fortune added at request time.")))
-    }
-  }
-  "A DbHandler" should "get random record" in {
-  }
-}