diff --git a/frameworks/Java/play2-java/play2-java-ebean-hikaricp/app/controllers/Application.java b/frameworks/Java/play2-java/play2-java-ebean-hikaricp/app/controllers/Application.java index d543b960b8f..48012ca6852 100644 --- a/frameworks/Java/play2-java/play2-java-ebean-hikaricp/app/controllers/Application.java +++ b/frameworks/Java/play2-java/play2-java-ebean-hikaricp/app/controllers/Application.java @@ -4,41 +4,56 @@ import java.util.Collections; import java.util.List; import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.concurrent.ThreadLocalRandom; +import javax.inject.Inject; + import models.Fortune; import models.World; import play.libs.Json; import play.mvc.Controller; import play.mvc.Result; +import utils.DatabaseExecutionContext; public class Application extends Controller { - public Result db() { - return ok(Json.toJson(getRandomWorlds(1).get(0))); + private final DatabaseExecutionContext dbEc; + + @Inject + public Application(final DatabaseExecutionContext dbEc) { + this.dbEc = dbEc; + } + + public CompletionStage db() { + return getRandomWorlds(1).thenApply(worlds -> ok(Json.toJson(worlds.get(0)))); } - public Result queries(final String queries) { - return ok(Json.toJson(getRandomWorlds(queryCount(queries)))); + public CompletionStage queries(final String queries) { + return getRandomWorlds(queryCount(queries)).thenApply(worlds -> ok(Json.toJson(worlds))); } - public Result fortunes() { - final List fortunes = Fortune.findAll(); - fortunes.add(new Fortune("Additional fortune added at request time.")); - Collections.sort(fortunes, (f1, f2) -> f1.message.compareTo(f2.message)); + public CompletionStage fortunes() { + return CompletableFuture.supplyAsync(() -> { + final List fortunes = Fortune.findAll(); + fortunes.add(new Fortune("Additional fortune added at request time.")); + Collections.sort(fortunes, (f1, f2) -> f1.message.compareTo(f2.message)); - return ok(views.html.fortunes.render(fortunes)); + return ok(views.html.fortunes.render(fortunes)); + }, dbEc); } - public Result update(final String queries) { - final List worlds = getRandomWorlds(queryCount(queries)); - final Random random = ThreadLocalRandom.current(); - for (final World world : worlds) { - world.randomNumber = (long) (random.nextInt(10000) + 1); - } + public CompletionStage update(final String queries) { + return getRandomWorlds(queryCount(queries)).thenApplyAsync(worlds -> { + final Random random = ThreadLocalRandom.current(); + for (final World world : worlds) { + world.randomNumber = (long) (random.nextInt(10000) + 1); + } - final List updatedWorlds = World.save(worlds); - return ok(Json.toJson(updatedWorlds)); + final List updatedWorlds = World.save(worlds); + return ok(Json.toJson(updatedWorlds)); + }, dbEc); } private int queryCount(final String queryCountString) { @@ -57,15 +72,17 @@ private int queryCount(final String queryCountString) { return queryCount; } - private List getRandomWorlds(final int n) { - final Random random = ThreadLocalRandom.current(); - final List worlds = new ArrayList<>(n); - for (int i = 0; i < n; ++i) { - long randomId = random.nextInt(10000) + 1; - final World world = World.find(randomId); - worlds.add(world); - } - return worlds; + private CompletionStage> getRandomWorlds(final int n) { + return CompletableFuture.supplyAsync(() -> { + final Random random = ThreadLocalRandom.current(); + final List worlds = new ArrayList<>(n); + for (int i = 0; i < n; ++i) { + long randomId = random.nextInt(10000) + 1; + final World world = World.find(randomId); + worlds.add(world); + } + return worlds; + }, dbEc); } } diff --git a/frameworks/Java/play2-java/play2-java-ebean-hikaricp/conf/application.conf b/frameworks/Java/play2-java/play2-java-ebean-hikaricp/conf/application.conf index 441fb488073..5afbb80f6d2 100644 --- a/frameworks/Java/play2-java/play2-java-ebean-hikaricp/conf/application.conf +++ b/frameworks/Java/play2-java/play2-java-ebean-hikaricp/conf/application.conf @@ -41,7 +41,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - TCP_FASTOPEN = 1 + "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 } } } @@ -50,8 +50,6 @@ play.server { akka { actor { default-dispatcher { - executor = "thread-pool-executor" - fork-join-executor { # one thread per core is enough # https://github.com/playframework/playframework/issues/7242#issuecomment-295215448 @@ -59,22 +57,18 @@ akka { # Information about the TechEmpower benchmark environment: https://www.techempower.com/benchmarks/#section=environment # The environment variable physical_cpu_count does NOT include the hyperthreaded cores! - parallelism-max = 14 - parallelism-max = ${?thread_count} + #parallelism-max = 14 + #parallelism-max = ${?thread_count} + parallelism-max = 64 task-peeking-mode="LIFO" # based on https://www.playframework.com/documentation/2.7.x/Migration24#Thread-pool-configuration } - # https://www.playframework.com/documentation/2.7.x/ThreadPools#Highly-synchronous - thread-pool-executor { - fixed-pool-size = 44 # db conn pool (29) + number of cores (14) + housekeeping (1) - } - # https://doc.akka.io/docs/akka/2.5.11/dispatchers.html#looking-up-a-dispatcher # Throughput defines the maximum number of messages to be # processed per actor before the thread jumps to the next actor. # Set to 1 for as fair as possible. - throughput = 1 + throughput = 64 } } } diff --git a/frameworks/Java/play2-java/play2-java-ebean-hikaricp/project/plugins.sbt b/frameworks/Java/play2-java/play2-java-ebean-hikaricp/project/plugins.sbt index 3ff00b511a8..76954a218a4 100644 --- a/frameworks/Java/play2-java/play2-java-ebean-hikaricp/project/plugins.sbt +++ b/frameworks/Java/play2-java/play2-java-ebean-hikaricp/project/plugins.sbt @@ -1,3 +1,3 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.2") addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "5.0.1") diff --git a/frameworks/Java/play2-java/play2-java-jooq-hikaricp/app/controllers/Application.java b/frameworks/Java/play2-java/play2-java-jooq-hikaricp/app/controllers/Application.java index ddf732d0c88..eeedde3cd6e 100644 --- a/frameworks/Java/play2-java/play2-java-jooq-hikaricp/app/controllers/Application.java +++ b/frameworks/Java/play2-java/play2-java-jooq-hikaricp/app/controllers/Application.java @@ -7,6 +7,8 @@ import java.util.Collections; import java.util.List; import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.concurrent.ThreadLocalRandom; import javax.inject.Inject; @@ -23,6 +25,7 @@ import play.db.Database; import play.mvc.Controller; import play.mvc.Result; +import utils.DatabaseExecutionContext; public class Application extends Controller { @@ -30,49 +33,53 @@ public class Application extends Controller { private static final JSONFormat JSON_FORMAT = JSONFormat.DEFAULT_FOR_RECORDS.recordFormat(RecordFormat.OBJECT); private final Database db; + private final DatabaseExecutionContext dbEc; @Inject - public Application(final Database db) { + public Application(final Database db, final DatabaseExecutionContext dbEc) { this.db = db; + this.dbEc = dbEc; } - public Result db() { - return ok(getRandomWorlds(1).get(0).formatJSON(JSON_FORMAT)).as(JSON); + public CompletionStage db() { + return getRandomWorlds(1).thenApply(worlds -> ok(worlds.get(0).formatJSON(JSON_FORMAT)).as(JSON)); } - public Result queries(final String queries) { - return ok(getRandomWorlds(queryCount(queries)).formatJSON(JSON_FORMAT)).as(JSON); + public CompletionStage queries(final String queries) { + return getRandomWorlds(queryCount(queries)).thenApply(worlds -> ok(worlds.formatJSON(JSON_FORMAT)).as(JSON)); } - public Result fortunes() { - final List fortunes = this.db.withConnection(connection -> { - return DSL.using(connection, DIALECT).select(FORTUNE.ID, FORTUNE.MESSAGE).from(FORTUNE).fetchInto(FortuneRecord.class); - }); - fortunes.add(new FortuneRecord(UInteger.valueOf(0), "Additional fortune added at request time.")); - Collections.sort(fortunes, (f1, f2) -> f1.getMessage().compareTo(f2.getMessage())); + public CompletionStage fortunes() { + return CompletableFuture.supplyAsync(() -> { + final List fortunes = this.db.withConnection(connection -> { + return DSL.using(connection, DIALECT).select(FORTUNE.ID, FORTUNE.MESSAGE).from(FORTUNE).fetchInto(FortuneRecord.class); + }); + fortunes.add(new FortuneRecord(UInteger.valueOf(0), "Additional fortune added at request time.")); + Collections.sort(fortunes, (f1, f2) -> f1.getMessage().compareTo(f2.getMessage())); - return ok(views.html.fortunes.render(fortunes)); + return ok(views.html.fortunes.render(fortunes)); + }, dbEc); } - public Result update(final String queries) { - final org.jooq.Result worlds = getRandomWorlds(queryCount(queries)); - - final Random random = ThreadLocalRandom.current(); - for (final WorldRecord world : worlds) { - world.setRandomnumber((random.nextInt(10000) + 1)); - } - - final int batchSize = 25; - final int batches = ((worlds.size() / batchSize) + 1); - this.db.withConnection(connection -> { - final DSLContext sql = DSL.using(connection, DIALECT); - for ( int i = 0 ; i < batches ; ++i ) { - sql.batchUpdate(worlds.subList(i * batchSize, Math.min((i + 1) * batchSize, worlds.size()))).execute(); + public CompletionStage update(final String queries) { + return getRandomWorlds(queryCount(queries)).thenApplyAsync(worlds -> { + final Random random = ThreadLocalRandom.current(); + for (final WorldRecord world : worlds) { + world.setRandomnumber((random.nextInt(10000) + 1)); } - return null; - }); - return ok(worlds.formatJSON(JSON_FORMAT)).as(JSON); + final int batchSize = 25; + final int batches = ((worlds.size() / batchSize) + 1); + this.db.withConnection(connection -> { + final DSLContext sql = DSL.using(connection, DIALECT); + for ( int i = 0 ; i < batches ; ++i ) { + sql.batchUpdate(worlds.subList(i * batchSize, Math.min((i + 1) * batchSize, worlds.size()))).execute(); + } + return null; + }); + + return ok(worlds.formatJSON(JSON_FORMAT)).as(JSON); + }, dbEc); } private int queryCount(final String queryCountString) { @@ -91,22 +98,24 @@ private int queryCount(final String queryCountString) { return queryCount; } - private org.jooq.Result getRandomWorlds(final int n) { - final Random random = ThreadLocalRandom.current(); - org.jooq.Result worlds = null; - for (int i = 0; i < n; ++i) { - long randomId = random.nextInt(10000) + 1; - final org.jooq.Result world = this.db.withConnection(connection -> { - return DSL.using(connection, DIALECT).selectFrom(WORLD).where(WORLD.ID.eq(UInteger.valueOf(randomId))).fetch(); - }); - - if(worlds == null) { - worlds = world; - } else { - worlds.add(world.get(0)); + private CompletionStage> getRandomWorlds(final int n) { + return CompletableFuture.supplyAsync(() -> { + final Random random = ThreadLocalRandom.current(); + org.jooq.Result worlds = null; + for (int i = 0; i < n; ++i) { + long randomId = random.nextInt(10000) + 1; + final org.jooq.Result world = this.db.withConnection(connection -> { + return DSL.using(connection, DIALECT).selectFrom(WORLD).where(WORLD.ID.eq(UInteger.valueOf(randomId))).fetch(); + }); + + if(worlds == null) { + worlds = world; + } else { + worlds.add(world.get(0)); + } } - } - return worlds; + return worlds; + }, dbEc); } } diff --git a/frameworks/Java/play2-java/play2-java-jooq-hikaricp/conf/application.conf b/frameworks/Java/play2-java/play2-java-jooq-hikaricp/conf/application.conf index 8d338099055..bb583ba38a3 100644 --- a/frameworks/Java/play2-java/play2-java-jooq-hikaricp/conf/application.conf +++ b/frameworks/Java/play2-java/play2-java-jooq-hikaricp/conf/application.conf @@ -41,7 +41,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - TCP_FASTOPEN = 1 + "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 } } } @@ -50,8 +50,6 @@ play.server { akka { actor { default-dispatcher { - executor = "thread-pool-executor" - fork-join-executor { # one thread per core is enough # https://github.com/playframework/playframework/issues/7242#issuecomment-295215448 @@ -59,22 +57,18 @@ akka { # Information about the TechEmpower benchmark environment: https://www.techempower.com/benchmarks/#section=environment # The environment variable physical_cpu_count does NOT include the hyperthreaded cores! - parallelism-max = 14 - parallelism-max = ${?thread_count} + #parallelism-max = 14 + #parallelism-max = ${?thread_count} + parallelism-max = 64 task-peeking-mode="LIFO" # based on https://www.playframework.com/documentation/2.7.x/Migration24#Thread-pool-configuration } - # https://www.playframework.com/documentation/2.7.x/ThreadPools#Highly-synchronous - thread-pool-executor { - fixed-pool-size = 44 # db conn pool (29) + number of cores (14) + housekeeping (1) - } - # https://doc.akka.io/docs/akka/2.5.11/dispatchers.html#looking-up-a-dispatcher # Throughput defines the maximum number of messages to be # processed per actor before the thread jumps to the next actor. # Set to 1 for as fair as possible. - throughput = 1 + throughput = 64 } } } diff --git a/frameworks/Java/play2-java/play2-java-jooq-hikaricp/project/plugins.sbt b/frameworks/Java/play2-java/play2-java-jooq-hikaricp/project/plugins.sbt index 8485f0836b2..17435f9155b 100644 --- a/frameworks/Java/play2-java/play2-java-jooq-hikaricp/project/plugins.sbt +++ b/frameworks/Java/play2-java/play2-java-jooq-hikaricp/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.2") diff --git a/frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/controllers/Application.java b/frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/controllers/Application.java index 601d73b89fd..3ee13e6c4e0 100644 --- a/frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/controllers/Application.java +++ b/frameworks/Java/play2-java/play2-java-jpa-hikaricp/app/controllers/Application.java @@ -4,6 +4,8 @@ import java.util.Collections; import java.util.List; import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.concurrent.ThreadLocalRandom; import javax.inject.Inject; @@ -14,41 +16,47 @@ import play.libs.Json; import play.mvc.Controller; import play.mvc.Result; +import utils.DatabaseExecutionContext; public class Application extends Controller { private final JPAApi jpa; + private final DatabaseExecutionContext dbEc; @Inject - public Application(final JPAApi jpa) { + public Application(final JPAApi jpa, final DatabaseExecutionContext dbEc) { this.jpa = jpa; + this.dbEc = dbEc; } - public Result db() { - return ok(Json.toJson(getRandomWorlds(1).get(0))); + public CompletionStage db() { + return getRandomWorlds(1).thenApply(worlds -> ok(Json.toJson(worlds.get(0)))); } - public Result queries(final String queries) { - return ok(Json.toJson(getRandomWorlds(queryCount(queries)))); + public CompletionStage queries(final String queries) { + return getRandomWorlds(queryCount(queries)).thenApply(worlds -> ok(Json.toJson(worlds))); } - public Result fortunes() { - final List fortunes = Fortune.findAll(this.jpa); - fortunes.add(new Fortune("Additional fortune added at request time.")); - Collections.sort(fortunes, (f1, f2) -> f1.message.compareTo(f2.message)); + public CompletionStage fortunes() { + return CompletableFuture.supplyAsync(() -> { + final List fortunes = Fortune.findAll(this.jpa); + fortunes.add(new Fortune("Additional fortune added at request time.")); + Collections.sort(fortunes, (f1, f2) -> f1.message.compareTo(f2.message)); - return ok(views.html.fortunes.render(fortunes)); + return ok(views.html.fortunes.render(fortunes)); + }, dbEc); } - public Result update(final String queries) { - final List worlds = getRandomWorlds(queryCount(queries)); - final Random random = ThreadLocalRandom.current(); - for (final World world : worlds) { - world.randomNumber = (long) (random.nextInt(10000) + 1); - } + public CompletionStage update(final String queries) { + return getRandomWorlds(queryCount(queries)).thenApplyAsync(worlds -> { + final Random random = ThreadLocalRandom.current(); + for (final World world : worlds) { + world.randomNumber = (long) (random.nextInt(10000) + 1); + } - final List updatedWorlds = World.save(worlds, this.jpa); - return ok(Json.toJson(updatedWorlds)); + final List updatedWorlds = World.save(worlds, this.jpa); + return ok(Json.toJson(updatedWorlds)); + }, dbEc); } private int queryCount(final String queryCountString) { @@ -67,15 +75,17 @@ private int queryCount(final String queryCountString) { return queryCount; } - private List getRandomWorlds(final int n) { - final Random random = ThreadLocalRandom.current(); - final List worlds = new ArrayList<>(n); - for (int i = 0; i < n; ++i) { - long randomId = random.nextInt(10000) + 1; - final World world = World.findById(randomId, this.jpa); - worlds.add(world); - } - return worlds; + private CompletionStage> getRandomWorlds(final int n) { + return CompletableFuture.supplyAsync(() -> { + final Random random = ThreadLocalRandom.current(); + final List worlds = new ArrayList<>(n); + for (int i = 0; i < n; ++i) { + long randomId = random.nextInt(10000) + 1; + final World world = World.findById(randomId, this.jpa); + worlds.add(world); + } + return worlds; + }, dbEc); } } diff --git a/frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/application.conf b/frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/application.conf index 38d94dc900c..2f8fe39025b 100644 --- a/frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/application.conf +++ b/frameworks/Java/play2-java/play2-java-jpa-hikaricp/conf/application.conf @@ -41,7 +41,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - TCP_FASTOPEN = 1 + "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 } } } @@ -50,8 +50,6 @@ play.server { akka { actor { default-dispatcher { - executor = "thread-pool-executor" - fork-join-executor { # one thread per core is enough # https://github.com/playframework/playframework/issues/7242#issuecomment-295215448 @@ -59,22 +57,18 @@ akka { # Information about the TechEmpower benchmark environment: https://www.techempower.com/benchmarks/#section=environment # The environment variable physical_cpu_count does NOT include the hyperthreaded cores! - parallelism-max = 14 - parallelism-max = ${?thread_count} + #parallelism-max = 14 + #parallelism-max = ${?thread_count} + parallelism-max = 64 task-peeking-mode="LIFO" # based on https://www.playframework.com/documentation/2.7.x/Migration24#Thread-pool-configuration } - # https://www.playframework.com/documentation/2.7.x/ThreadPools#Highly-synchronous - thread-pool-executor { - fixed-pool-size = 44 # db conn pool (29) + number of cores (14) + housekeeping (1) - } - # https://doc.akka.io/docs/akka/2.5.11/dispatchers.html#looking-up-a-dispatcher # Throughput defines the maximum number of messages to be # processed per actor before the thread jumps to the next actor. # Set to 1 for as fair as possible. - throughput = 1 + throughput = 64 } } } diff --git a/frameworks/Java/play2-java/play2-java-jpa-hikaricp/project/plugins.sbt b/frameworks/Java/play2-java/play2-java-jpa-hikaricp/project/plugins.sbt index 8485f0836b2..17435f9155b 100644 --- a/frameworks/Java/play2-java/play2-java-jpa-hikaricp/project/plugins.sbt +++ b/frameworks/Java/play2-java/play2-java-jpa-hikaricp/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.2") diff --git a/frameworks/Java/play2-java/play2-java/conf/application.conf b/frameworks/Java/play2-java/play2-java/conf/application.conf index 51ef4a4361f..3c2411c27af 100644 --- a/frameworks/Java/play2-java/play2-java/conf/application.conf +++ b/frameworks/Java/play2-java/play2-java/conf/application.conf @@ -41,7 +41,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - TCP_FASTOPEN = 1 + "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 } } } @@ -57,8 +57,9 @@ akka { # Information about the TechEmpower benchmark environment: https://www.techempower.com/benchmarks/#section=environment # The environment variable physical_cpu_count does NOT include the hyperthreaded cores! - parallelism-max = 14 - parallelism-max = ${?thread_count} + #parallelism-max = 14 + #parallelism-max = ${?thread_count} + parallelism-max = 64 task-peeking-mode="LIFO" # based on https://www.playframework.com/documentation/2.7.x/Migration24#Thread-pool-configuration } diff --git a/frameworks/Java/play2-java/play2-java/project/plugins.sbt b/frameworks/Java/play2-java/play2-java/project/plugins.sbt index 8485f0836b2..17435f9155b 100644 --- a/frameworks/Java/play2-java/play2-java/project/plugins.sbt +++ b/frameworks/Java/play2-java/play2-java/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.2") diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm/app/controllers/Application.scala b/frameworks/Scala/play2-scala/play2-scala-anorm/app/controllers/Application.scala index 373f759a070..a8048d9d677 100644 --- a/frameworks/Scala/play2-scala/play2-scala-anorm/app/controllers/Application.scala +++ b/frameworks/Scala/play2-scala/play2-scala-anorm/app/controllers/Application.scala @@ -3,26 +3,28 @@ package controllers import javax.inject.{Inject, Singleton} import play.api.mvc._ +import play.mvc.Http import play.api.libs.json.Json import java.util.concurrent._ import models.{WorldDAO, FortunesDAO, World, Fortune} import utils.DbOperation +import scala.concurrent.{Future, ExecutionContext} @Singleton() -class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, dbOperation: DbOperation, val controllerComponents: ControllerComponents) +class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, dbOperation: DbOperation, val controllerComponents: ControllerComponents)(implicit ec: ExecutionContext) extends BaseController { - def getRandomWorlds(n: Int): Seq[World] = dbOperation.syncDbOp { implicit connection => + def getRandomWorlds(n: Int): Future[Seq[World]] = dbOperation.asyncDbOp { implicit connection => for (_ <- 1 to n) yield { worldDAO.findById(getNextRandom) } } - def getFortunes: Seq[Fortune] = dbOperation.syncDbOp { implicit connection => + def getFortunes: Future[Seq[Fortune]] = dbOperation.asyncDbOp { implicit connection => fortunesDAO.getAll } - def updateWorlds(n: Int): Seq[World] = dbOperation.syncDbOp { implicit connection => + def updateWorlds(n: Int): Future[Seq[World]] = dbOperation.asyncDbOp { implicit connection => for(_ <- 1 to n) yield { val world = worldDAO.findById(getNextRandom) val updatedWorld = world.copy(randomNumber = getNextRandom) @@ -42,23 +44,31 @@ class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, dbOpe import models.WorldJsonHelpers.toJson - def db = Action { - Ok(Json.toJson(getRandomWorlds(1).head)) + def db = Action.async { + getRandomWorlds(1).map { worlds => + Ok(Json.toJson(worlds.head)) + } } - def queries(countString: String) = Action { + def queries(countString: String) = Action.async { val n = parseCount(countString) - Ok(Json.toJson(getRandomWorlds(n))) + getRandomWorlds(n).map { worlds => + Ok(Json.toJson(worlds)) + } } - def fortunes() = Action { - val appendedFortunes = Fortune(0, "Additional fortune added at request time.") :: getFortunes.to[List] - Ok(views.html.fortune(appendedFortunes)) + def fortunes() = Action.async { + getFortunes.map { dbFortunes => + val appendedFortunes = Fortune(0, "Additional fortune added at request time.") :: dbFortunes.to[List] + Ok(views.html.fortune(appendedFortunes)) + } } - def update(queries: String) = Action { + def update(queries: String) = Action.async { val n = parseCount(queries) - Ok(Json.toJson(updateWorlds(n))) + updateWorlds(n).map { worlds => + Ok(Json.toJson(worlds)) + } } private def parseCount(s: String): Int = { diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm/app/utils/DbOperation.scala b/frameworks/Scala/play2-scala/play2-scala-anorm/app/utils/DbOperation.scala index 0d3ca45d17b..896031225f0 100644 --- a/frameworks/Scala/play2-scala/play2-scala-anorm/app/utils/DbOperation.scala +++ b/frameworks/Scala/play2-scala/play2-scala-anorm/app/utils/DbOperation.scala @@ -12,18 +12,20 @@ import scala.concurrent.Future @Singleton class DbOperation @Inject() (protected val db: Database, - configuration: Configuration) { + configuration: Configuration, dbEc: DatabaseExecutionContext) { /** * Run a DB operation in the DB context. */ - def syncDbOp[T](op: Connection => T): T = { + 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. - db.withConnection { connection => op(connection) } + Future { + db.withConnection { connection => op(connection) } + }(dbEc) } } diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf b/frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf index 39be8705643..b3f5576dc71 100755 --- a/frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf +++ b/frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf @@ -36,7 +36,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - TCP_FASTOPEN = 1 + "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 } } } @@ -45,8 +45,6 @@ play.server { akka { actor { default-dispatcher { - executor = "thread-pool-executor" - fork-join-executor { # one thread per core is enough # https://github.com/playframework/playframework/issues/7242#issuecomment-295215448 @@ -54,22 +52,18 @@ akka { # Information about the TechEmpower benchmark environment: https://www.techempower.com/benchmarks/#section=environment # The environment variable physical_cpu_count does NOT include the hyperthreaded cores! - parallelism-max = 14 - parallelism-max = ${?thread_count} + #parallelism-max = 14 + #parallelism-max = ${?thread_count} + parallelism-max = 64 task-peeking-mode="LIFO" # based on https://www.playframework.com/documentation/2.7.x/Migration24#Thread-pool-configuration } - # https://www.playframework.com/documentation/2.7.x/ThreadPools#Highly-synchronous - thread-pool-executor { - fixed-pool-size = 44 # db conn pool (29) + number of cores (14) + housekeeping (1) - } - # https://doc.akka.io/docs/akka/2.5.11/dispatchers.html#looking-up-a-dispatcher # Throughput defines the maximum number of messages to be # processed per actor before the thread jumps to the next actor. # Set to 1 for as fair as possible. - throughput = 1 + throughput = 64 } } } diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt b/frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt index 8485f0836b2..17435f9155b 100644 --- a/frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.2") diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt index 81933e7e362..e36a97a30d6 100644 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt @@ -6,9 +6,11 @@ lazy val root = (project in file(".")).enablePlugins(PlayScala, PlayNettyServer) scalaVersion := "2.12.8" +resolvers += Resolver.sonatypeRepo("snapshots") + libraryDependencies ++= Seq( - "org.reactivemongo" %% "play2-reactivemongo" % "0.16.2-play27", - "org.reactivemongo" %% "reactivemongo-play-json" % "0.16.2-play27", + "org.reactivemongo" %% "play2-reactivemongo" % "0.17.0-play27-SNAPSHOT", + "org.reactivemongo" %% "reactivemongo-play-json" % "0.17.0-play27-SNAPSHOT", "com.softwaremill.macwire" %% "macros" % "2.3.0", "com.softwaremill.macwire" %% "util" % "2.3.0" ) diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf index 2943b726e27..1af0ce74ca9 100755 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf @@ -32,7 +32,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - TCP_FASTOPEN = 1 + "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 } } } @@ -48,8 +48,9 @@ akka { # Information about the TechEmpower benchmark environment: https://www.techempower.com/benchmarks/#section=environment # The environment variable physical_cpu_count does NOT include the hyperthreaded cores! - parallelism-max = 14 - parallelism-max = ${?thread_count} + #parallelism-max = 14 + #parallelism-max = ${?thread_count} + parallelism-max = 64 task-peeking-mode="LIFO" # based on https://www.playframework.com/documentation/2.7.x/Migration24#Thread-pool-configuration } diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt index 8485f0836b2..17435f9155b 100644 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.2") diff --git a/frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf b/frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf index d3172708654..af3a0b0cc4f 100755 --- a/frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf +++ b/frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf @@ -36,7 +36,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - TCP_FASTOPEN = 1 + "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 } } } @@ -52,8 +52,9 @@ akka { # Information about the TechEmpower benchmark environment: https://www.techempower.com/benchmarks/#section=environment # The environment variable physical_cpu_count does NOT include the hyperthreaded cores! - parallelism-max = 14 - parallelism-max = ${?thread_count} + #parallelism-max = 14 + #parallelism-max = ${?thread_count} + parallelism-max = 64 task-peeking-mode="LIFO" # based on https://www.playframework.com/documentation/2.7.x/Migration24#Thread-pool-configuration } diff --git a/frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt b/frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt index 8485f0836b2..17435f9155b 100644 --- a/frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.2") diff --git a/frameworks/Scala/play2-scala/play2-scala/conf/application.conf b/frameworks/Scala/play2-scala/play2-scala/conf/application.conf index 17b13d69180..04ead9079c0 100755 --- a/frameworks/Scala/play2-scala/play2-scala/conf/application.conf +++ b/frameworks/Scala/play2-scala/play2-scala/conf/application.conf @@ -36,7 +36,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - TCP_FASTOPEN = 1 + "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 } } } @@ -52,8 +52,9 @@ akka { # Information about the TechEmpower benchmark environment: https://www.techempower.com/benchmarks/#section=environment # The environment variable physical_cpu_count does NOT include the hyperthreaded cores! - parallelism-max = 14 - parallelism-max = ${?thread_count} + #parallelism-max = 14 + #parallelism-max = ${?thread_count} + parallelism-max = 64 task-peeking-mode="LIFO" # based on https://www.playframework.com/documentation/2.7.x/Migration24#Thread-pool-configuration } diff --git a/frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt b/frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt index 8485f0836b2..17435f9155b 100644 --- a/frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt +++ b/frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.0") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.2")