LiftActor future with callback?

181 views
Skip to first unread message

Diego Medina

unread,
Apr 14, 2012, 3:48:35 PM4/14/12
to Lift
Hi,

Is there a way to have a callback function send to a LiftActor, along
with a message, so that when the LiftActor is done processing the
message, it will execute my callback?
What I'm looking for is something similar (or exactly) like Twitter's
finagle Future with callback.
https://github.com/twitter/finagle#Future%20Callbacks

As an example:

val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
val responseFuture: Future[HttpResponse] = client(request)
responseFuture onSuccess { responseFuture =>
println(responseFuture)
}

so if responseFuture executes and all goes well, the println will be called.

My real use case is this:

On my snippet I send a message to an actor A, this message has a key
form a key-> value map.
The value is a reference to another LiftActor B, so once A selects the
actor B, it needs to send B another message, so B can do its job.

One limitation I have is that I cannot modify the final message I send
to B, if I could I would just do something like:

case class ComposedMessage(key: String, msg: String)

So, if we had a Future with Callback in Lift I imagine I could do:

case class Message(msg: String)
case class Key(key: String)

val actorResponseFuture= LiftActorA !< Key("123")
actorResponseFuture onSuccess { responseActor =>
responseActor ! Message("Do this job")
}


So I guess my question now is two fold:

1- Can this be done today?
2- If not, would it be useful to add such a feature?

And just in case it wasn't clear, I'm trying to do it this way so that
the thread my snippet is in does not block while all that processing
is happening.

Thanks

Diego


--
Diego Medina
Lift/Scala Developer
di...@fmpwizard.com
http://www.fmpwizard.com

Antonio Salazar Cardozo

unread,
Apr 15, 2012, 9:42:06 PM4/15/12
to lif...@googlegroups.com
Is there a reason you can't just bundle the callback with the message? Or do the futures have specific synchronization semantics?
Thanks,
Antonio

Diego Medina

unread,
Apr 15, 2012, 9:54:43 PM4/15/12
to lif...@googlegroups.com
I think I ended up doing something similar to what you said.
I am not using actors, but a singleton with a method:

def send(key: Box[String], msg: Any): Unit ={
Schedule.schedule(() => dispatchersFor(key) ! msg, 0 seconds)
}

so from outside I call it:

NamedCometListener.send(name, registerCometActor(this, name))

and if I understood Schedule correctly, the send method returns pretty
fast, not waiting for the result of
dispatchersFor(key)

But I still wonder if it would make for a useful feature, how would
you send the callback with your message in the future?


Thanks

Diego

> --
> Lift, the simply functional web framework: http://liftweb.net
> Code: http://github.com/lift
> Discussion: http://groups.google.com/group/liftweb
> Stuck? Help us help you:
> https://www.assembla.com/wiki/show/liftweb/Posting_example_code

David Pollak

unread,
Apr 16, 2012, 12:31:29 PM4/16/12
to lif...@googlegroups.com
If you use a foreach (or a for comprehension without a yield) on a future, the computation will be resumed on a separate thread when the future is satisfied:

val result: LAFuture[Result] = longComputation

result.foreach(r => myActor ! r) // returns immediately and when the future is satisfied, the message send it processed.

--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code



--
Visi.Pro, Cloud Computing for the Rest of Us http://visi.pro
Lift, the simply functional web framework http://liftweb.net

AGYNAMIX Torsten Uhlmann

unread,
Apr 16, 2012, 12:58:03 PM4/16/12
to lif...@googlegroups.com
David,

thanks for explaining these mechanisms!

May I ask for a short example of "longComputation". I understand this is the way to do it, yet there are some steps I do not fully get:

val result: LAFuture[Result] = new LAFuture[Result] // is this the way to create a new future?
result.satisfy(?) 

Here's my problem: from the source I see satisfy takes a parameter T, not a function. So I simply do not get how and why this parameter T is then forked off into another thread with LAScheduler.execute(…) If it's just a parameter then it's already resolved, right. I think right here is my problem...

Could you explain this step, please?

Thanks,
Torsten.

David Pollak

unread,
Apr 16, 2012, 1:15:59 PM4/16/12
to lif...@googlegroups.com
def longComputation: LAFuture[Result] = {
  val ret: LAFuture[Result] = new LAFuture()

  Schedule(() => {
    // do some stuff that takes a long time and maybe even forks a bunch of threads
    val r: Result = ... the result of the computation
    ret.satisfy(r)
  })

  ret

Diego Medina

unread,
Apr 16, 2012, 2:07:34 PM4/16/12
to lif...@googlegroups.com
On Mon, Apr 16, 2012 at 12:31 PM, David Pollak
<feeder.of...@gmail.com> wrote:
> If you use a foreach (or a for comprehension without a yield) on a future,
> the computation will be resumed on a separate thread when the future is
> satisfied:
>
> val result: LAFuture[Result] = longComputation
>
> result.foreach(r => myActor ! r) // returns immediately and when the future
> is satisfied, the message send it processed.

Uh, nice!

This is just what I was looking for. Thanks!
And added to the wiki
http://www.assembla.com/spaces/liftweb/wiki/Cool_Tips

Regards,

Diego

Reply all
Reply to author
Forward
0 new messages