Skip to content

Instantly share code, notes, and snippets.

@Joe-Edwards
Created June 28, 2016 16:55
Show Gist options
  • Save Joe-Edwards/e447f94e948954499325d4b96122f4ee to your computer and use it in GitHub Desktop.
Save Joe-Edwards/e447f94e948954499325d4b96122f4ee to your computer and use it in GitHub Desktop.
Spec to demonstrate deadlocking in a route by awaiting toStrict
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.client.RequestBuilding
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.{Directives, Route}
import akka.stream.ActorMaterializer
import org.specs2.mutable.Specification
import scala.annotation.tailrec
import scala.concurrent.{Await, TimeoutException}
import scala.concurrent.duration._
class ToStrictRoutingSpec extends Specification with Directives with RequestBuilding {
"Blocking on toStrict" should {
"not deadlock a server" in {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
import system.dispatcher
val route: Route = extractRequest { request =>
request.entity match {
case strict: HttpEntity.Strict =>
// Not interested in Strict entities - they will always work
complete(StatusCodes.UnprocessableEntity)
case _ =>
try {
Await.result(request.entity.toStrict(5.seconds), 10.seconds)
complete(StatusCodes.OK)
} catch {
case timeout: TimeoutException if timeout.getMessage.contains("toStrict") =>
// The ToStrict stage failed
complete(StatusCodes.ServiceUnavailable)
case timeout: TimeoutException =>
// The Await failed
complete(StatusCodes.GatewayTimeout)
}
}
}
val binding = Await.result(Http().bindAndHandle(route, "0.0.0.0", 0), 2.seconds)
@tailrec def makeRequestWithNonStrictEntity(retries: Int = 0): HttpResponse = {
if (retries > 10) throw new Exception("Couldn't get a non-strict entity") else {
val response = Await.result(
Http().singleRequest(HttpRequest(
HttpMethods.POST,
s"http://localhost:${binding.localAddress.getPort}",
entity = "x" * 100 * 1000)),
15.seconds)
if (response.status == StatusCodes.UnprocessableEntity)
makeRequestWithNonStrictEntity(retries + 1)
else
response
}
}
makeRequestWithNonStrictEntity().status mustEqual StatusCodes.OK
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment