简体   繁体   中英

Play framework action response delayed when creating multiple futures

In the following action it should return response immediately after hitting URL but instead it waits till all the Future blocks are started and then only sends response. It waits till "Starting for group 10" is logged in console even though "Returning from action" is logged immediately after hitting URL.

def test = Action { implicit request =>
    Future.successful(0 to 150).foreach { items =>
      items.grouped(15).zipWithIndex.foreach{ itemGroupWithIndex =>
        val (itemGroup, index) = itemGroupWithIndex
        Future {
          logger.info("************** Starting for group " + index)
          itemGroup.foreach { item =>
            Thread.sleep(1000)
            logger.info("Completed for item " + item)
          }
        }
      }
    }
    logger.info("************** Returning from action **************")
    Ok(views.html.test("test page"))
}

I am not able to understand reason behind this delay and how can i make this action send response immediately.

Play framework version 2.5.9

Your Action is not Async. You have a synchronous endpoint which is why you see the Returning from action printed immediately on the console. You should probably use the Action.async as your processing type. Using async Actions will drastically improve the overall performance of your application and is highly recommended when building high throughput and responsive web applications.

Two points in your code needs to change

  1. Asynchronous Action : Because you are using Future, the action should be asynchronous: Action.async{...} .

  2. No Blocking Code : The whole point of using Future and asynchronous programming is not to have a code that "blocks" the execution. So I suggest to remove the Thread.sleep(1000) part of the code.

Note that if you write your code non-blocking way; whenever the action method get the result; it will perform the required action(s), such as logging or providing the view.

This is because there are race conditions in your Futures.

You need to ensure that you are returning a single Future[T] and not a Future[Future[T]] (or any layered variances).

If the Futures are independent of each other, use Future.sequence

example:

 def future: Future[String] = Future.successful("hi")


 def action = Action.async { _ =>
   val futures: Seq[Future[String]] = (1 to 50).map(_ => future()).toSeq
   val oneFuture = Future.sequence(futures)
   oneFuture
 }

This will avoid race conditions

FYI, this has nothing to do with the Play framework. This is concurrent programming in scala.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM