Play Framework异步控制器阻止对同一控制器的后续调用

时间:2018-11-01 13:45:11

标签: scala asynchronous playframework

我的目标是从异步控制器中进行一些数据库查询,然后返回答案。

我正在处理示例项目,目前仅通过睡眠来模拟数据库查询,但是我注意到的是,无论我做什么,REST接口甚至不会在第二个查询开始之前就开始第二个查询的睡眠。一完成。 例如:如果我从浏览器的一个选项卡调用REST接口,然后再从另一个选项卡调用1秒钟,我希望第二个也能在10秒内得到答复,但实际上是19秒。

而且似乎也没有使用“ database-io”池:

  

1:application-akka.actor.default-dispatcher-2

     

2:application-akka.actor.default-dispatcher-5

我的代码:

@Singleton
class AsyncController @Inject()(cc: ControllerComponents, actorSystem: ActorSystem) extends AbstractController(cc) {

  implicit val executionContext = actorSystem.dispatchers.lookup("database-io")

  def message = Action.async {
    getFutureMessage().map { msg => Ok(msg) }
  }

  private def getFutureMessage(): Future[String] = {
    val defaultThreadPool = Thread.currentThread().getName;
    println(s"""1: $defaultThreadPool""")

    val promise: Promise[String] = Promise[String]()
    actorSystem.scheduler.scheduleOnce(0 second) {
      val blockingPool = Thread.currentThread().getName;
      println(s"""2: $blockingPool""")

      Thread.sleep(10000)
      promise.success("Hi!")
    }(actorSystem.dispatcher)
    promise.future
  }

}

2 个答案:

答案 0 :(得分:0)

此行为可能是两个原因:

  1. 您使用开发模式(1个线程),或者仅针对一个线程配置了产品配置。
  2. 浏览器将阻止第二个请求,直到收到第一个请求的响应为止。这句话:“如果我从浏览器的一个选项卡调用REST接口。”尝试从不同的浏览器执行相同的操作。

答案 1 :(得分:0)

您需要避免阻塞代码。基本上:

  1. 您可以使用一种返回Future的方法。

  2. 您映射到其中。

  3. 您可以恢复AppName结果可能带来的任何失败。

让我说:

Future

然后将其映射到其中:

def userAge (userId: String): Future[Int] = ???

请注意,如果您有多个通话,则另一个userAge.map{ age => ??? //everything is ok }.recover{ case e: Throwable => ??? //Do something when it fails 会变成map,因为您想要flatMap而不是Future[...]