Implementing long polling in scala and play 2.0 with akka
Asked Answered
D

2

13

I'm implementing long polling in Play 2.0 in potentially a distributed environment. The way I understand it is that when Play gets a request, it should suspend pending notification of an update then go to the db to fetch new data and repeat. I started looking at the chat example that Play 2.0 offers but it's in websocket. Furthermore it doesn't look like it's capable of being distributed. So I thought I will use Akka's event bus. I took the eventstream implementation and replicated my own with LookupClassification. However I'm stumped as to how I'm gonna get a message back (or for that matter, what should be the subscriber instead of ActorRef)?

EventStream implementation: https://github.com/akka/akka/blob/master/akka-actor/src/main/scala/akka/event/EventStream.scala

Digitize answered 10/4, 2012 at 14:24 Comment(0)
P
5

I am not sure that is what you are looking for, but there is quite a simple solution in the comet-clock sample, that you can adapt to use AKKA actors. It uses an infinite iframe instead of long polling. I have used an adapted version for a more complex application doing multiple DB calls and long computation in AKKA actors and it works fine.

  def enum = Action {
    //get your actor
    val myActorRef = Akka.system.actorOf(Props[TestActor]) 

   //do some query to your DB here. Promise.timeout is to simulate a blocking call
   def getDatabaseItem(id: Int): Promise[String] = { Promise.timeout("test", 10 milliseconds) } 

    //test iterator, you will want something smarter here
    val items1 = 1 to 10 toIterator

    // this is a very simple enumerator that takes ints from an existing iterator (for an http request parameters for instance) and do some computations
    def myEnum(it: Iterator[Int]): Enumerator[String] = Enumerator.fromCallback[String] { () =>
      if (!items1.hasNext)
        Promise.pure[Option[String]](None) //we are done with our computations
      else {

        // get the next int, query the database and compose the promise with a further query to the AKKA actor
        getDatabaseItem(items1.next).flatMap { dbValue =>
          implicit val timeout = new Timeout(10 milliseconds)
          val future = (myActorRef ? dbValue) mapTo manifest[String]

          // here we convert the AKKA actor to the right Promise[Option] output
          future.map(v => Some(v)).asPromise
        }
      }
    }

    // finally we stream the result to the infinite iframe. 
    // console.log is the javascript callback, you will want something more interesting.
    Ok.stream(myEnum(items1) &> Comet(callback = "console.log"))
  }

Note that this fromCallback doesn't allow you to combine enumerators with "andThen", there is in the trunk version of play2 a generateM method that might be more appropriate if you want to use combinations.

It's not long polling, but it works fine.

Plutus answered 25/5, 2012 at 14:4 Comment(0)
V
1

I stumbled on your question while looking for the same thing.

I found the streaming solution unsatisfying as they caused "spinner of death" in webkit browser (i.e. shows it is loading all the time)

Anyhow, didn't have any luck finding good examples but I managed to create my own proof-of-concept using promises: https://github.com/kallebertell/longpoll

Vasoconstrictor answered 13/11, 2012 at 20:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.