Question

To feed Play response I want to pass Enumerator to result's feed method. I need to pass a state from produce/consume iteration step to the next step (or to keep state). Here http://engineering.klout.com/2013/01/iteratees-in-big-data-at-klout/ I have found an example but am not sure it is thread-safe:

def pagingEnumerator(url:String):Enumerator[JsValue]={
        var maybeNextUrl = Some(url) //Next url to fetch
        Enumerator.fromCallback[JsValue] ( retriever = {

        val maybeResponsePromise =
            maybeNextUrl map { nextUrl=>
                WS.url(nextUrl).get.map { reponse =>
                    val json = response.json
                    maybeNextUrl = (json \ "next_url").asOpt[String]
                    val code = response.status //Potential error handling here
                    json
                }
            }

        maybeResponsePromise match {
            case Some(responsePromise) => responsePromise map Some.apply
            case None                  => PlayPromise pure None
        }
    })
}

What is you way to add a state to Play Enumerator? Is this example thread-safe?

(in the above example old Play API related to Promise/Future is used; let's neglect this fact as far as it doesn't influence the issue itself)

Was it helpful?

Solution

You should use Enumerator.unfoldM:

Enumerator.unfoldM(Some(firstURL)) { maybeNextUrl =>
  maybeNextUrl map { nextUrl =>
    WS.url(nextUrl).get.map { response =>
      val json = response.json
      val newUrl = (json \ "next_url").asOpt[String]
      val code = response.status //Potential error handling here
      Some((newUrl, json))
    }
  } getOrElse (Future.successful(None))
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top