Pergunta

I have a page that is populated by data that I get using different calls to distant servers. Some requests take longer than others, the way I do things now is that I do all the calls at once and wrap the whole thing in a Future, then put the the whole thing in a Action.async for Play to handle.

This, theoretically, does the job but I don't want my users to be waiting a long time and instead start loading the page part by part. Meaning that as soon as data is available for a given request to a distant server, it should be sent to the client as Json or whatever.

I was able to partially achieve this using EventSource by modifying Play's event-source sample by doing something like this:

Ok.chunked((enumerator1  &> EventSource()) >- (enumerator2  &> EventSource())).as("text/event-stream")

and the enumerators as follows:

val enumerator1: Enumerator[String] = Enumerator.generateM{
   Future[Option[String]]{Thread.sleep(1500); Some("Hello")}
}

val enumerator2: Enumerator[String] = Enumerator.generateM{
   Future[Option[String]]{Thread.sleep(2000); Some("World!")}
}

As you probably have guessed, I was expecting to have "Hello" after 1.5s and then "World!" 0.5s later sent to the client, but I ended up receiving "Hello" every 1.5s and "World!" every 2s.

My questions are:

  1. Is there a way to stop sending an information once it has been correctly delivered to the client using the method above?

  2. Is there a better way to achieve what I want?

Foi útil?

Solução

You don't want generateM, it's for building enumerators that can return multiple values. generateM takes a function that either returns a Some, to produce the next value for the Enumerator, or None, to signal that the Enumerator is complete. Because your function always returns Some, you create Enumerators that are infinite in length.

You just want to convert a Future into an Enumerator, to create an Enumerator with a single element:

Enumerator.flatten(future.map(Enumerator(_)))

Also, you can interleave your enumerators and then feed the result into EventSource(). Parenthesis are unnecessary as well (methods that start with > have precedence over methods with &).

enumerator1  >- enumerator2 &> EventSource()
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top