Hi,
My question is regarding Johannes Rudolph's comment about it being a workaround:
Using toStrictEntity is basically only a workaround and not a solution because it will mean that all entity data will be buffered in memory which means that your server will need more memory per concurrent request than necessary.
Let's say you have the need to log the complete request payload of all requests coming in to a service. If you want to allow the logging logic to fully consume to request payload and still allow the entity to be unmarshalled to the desired object later on, what would be another way to ensure this never fails other than using toStrict, forcing the entire payload into memory and allowing it to be consumed more than once?
For example, consider the following route:
val route = extractExecutionContext & extractMaterializer & extractLog { (ec, mat, log) =>
logRequest(LoggingMagnet(_ => logRequestDetails(_)(ec, mat, log))) {
path("someapi") {
post {
entity(as[SomeInputClass]) { input =>
// do something with input
}
}
}
}
}
def logRequestDetails(req: HttpRequest)(implicit ec: ExecutionContext, materializer: Materializer, log: LoggingAdapter): Unit =
Unmarshal(req.entity).to[String].map(b => s"The request body is $b").onComplete {
case Failure(e) => log.error(e, "Error")
}
This is obviously a contrived example, but this logs the request body. It works, but we've seen such a pattern inconsistently yield java.lang.IllegalStateException: Substream Source cannot be materialized more than once errors. Isn't this a case where converting to a strict entity the correct way to address such problems, i.e. allow the request entity to be consumed more than once? If not, what would be the correct way?
Thanks for any insight you might have!
Yannick