Skip to content

Commit

Permalink
Performance optimizations
Browse files Browse the repository at this point in the history
When deferring is disabled (the default) we shouldn't use a lambda
but just a normal method because it's faster (than lambdas/invokedynamic).
Also akka-http performs much better with the ec of the materializer
  • Loading branch information
mkurz committed Aug 17, 2023
1 parent 046f85e commit f7ad9a8
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ import play.core.server.common.ServerResultUtils
import play.core.server.ssl.ServerSSLEngine
import play.core.server.Server.ServerStoppedReason
import play.core.ApplicationProvider
import play.core.Execution.trampoline

/**
* Starts a Play server using Akka HTTP.
Expand Down Expand Up @@ -456,8 +455,7 @@ class AkkaHttpServer(context: AkkaHttpServer.Context) extends Server {

// This lambda captures the source and the (implicit) materializer.
// Meaning no matter if parsing is deferred, it always uses the same materializer.
val invokeAction: (Future[Accumulator[ByteString, Result]], Boolean) => Future[Result] =
(futureAcc, deferBodyParsing) =>
def invokeAction(futureAcc: Future[Accumulator[ByteString, Result]], deferBodyParsing: Boolean): Future[Result] =
// here we use FastFuture so the flatMap shouldn't actually need the executionContext
futureAcc.fast
.flatMap { actionAccumulator =>
Expand All @@ -472,7 +470,7 @@ class AkkaHttpServer(context: AkkaHttpServer.Context) extends Server {
}
}
}
}(trampoline)
}(mat.executionContext)
.recoverWith {
case _: EntityStreamSizeException =>
errorHandler.onClientError(
Expand All @@ -482,12 +480,12 @@ class AkkaHttpServer(context: AkkaHttpServer.Context) extends Server {
)
case e: Throwable =>
errorHandler.onServerError(taggedRequestHeader, e)
}(trampoline)
}(mat.executionContext)

val deferBodyParsing = deferredBodyParsingAllowed &&
Server.routeModifierDefersBodyParsing(serverConfig.underlying.getBoolean("deferBodyParsing"), taggedRequestHeader)
val futureAcc: Future[Accumulator[ByteString, Result]] = Future(action(if (deferBodyParsing) {
taggedRequestHeader.addAttr(RequestAttrKey.DeferredBodyParserInvoker, invokeAction)
taggedRequestHeader.addAttr(RequestAttrKey.DeferredBodyParserInvoker, invokeAction _)
} else {
taggedRequestHeader
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,7 @@ private[play] class PlayRequestHandler(

// This lambda captures the Netty HttpRequest and the (implicit) materializer.
// Meaning no matter if parsing is deferred, it always uses the same materializer.
val invokeAction: (Future[Accumulator[ByteString, Result]], Boolean) => Future[Result] =
(actionFuture, deferBodyParsing) =>
def invokeAction(actionFuture: Future[Accumulator[ByteString, Result]], deferBodyParsing: Boolean): Future[Result] =
actionFuture
.flatMap { acc =>
if (deferBodyParsing) {
Expand All @@ -318,18 +317,18 @@ private[play] class PlayRequestHandler(
case Some(source) => acc.run(source)
}
}
}(trampoline)
}
.recoverWith {
case error =>
logger.error("Cannot invoke the action", error)
errorHandler(tryApp).onServerError(requestHeader, error)
}(trampoline)
}

val deferBodyParsing = deferredBodyParsingAllowed &&
Server.routeModifierDefersBodyParsing(deferBodyParsingGlobal, requestHeader)
// Execute the action on the Play default execution context
val actionFuture = Future(action(if (deferBodyParsing) {
requestHeader.addAttr(RequestAttrKey.DeferredBodyParserInvoker, invokeAction)
requestHeader.addAttr(RequestAttrKey.DeferredBodyParserInvoker, invokeAction _)
} else {
requestHeader
}))(mat.executionContext)
Expand Down

0 comments on commit f7ad9a8

Please sign in to comment.