Question regarding passing LAFutures into Roundtrips

63 views
Skip to first unread message

Andreas Alexelis

unread,
Mar 24, 2016, 1:31:22 PM3/24/16
to Lift
Hi all,

I have a question regarding round trips: I am using Lift 3 with Slick 3 for persistance and I am trying to pass a Future I get back from a Slick query, after transforming it to an LAFuture, as response to a round trip, something along the lines of the following:

object MyRTSnippet (in: NodeSeq): NodeSeq = {
  
  def render = {
    def doSave(item: JValue): LAFuture[JValue] = {
    getFutureFromSlick(item).toLAFuture()
  }

  val script = SetExp(JsVar("window", "backend"), sess.buildRoundtrip(List[RoundTripInfo](
    "save" -> doSave _
)))
S.appendGlobalJs(script)
  in
  }
}

However, I don't seem to get the result on the client, instead I get success with an empty JSON:
...
lift.sendEvent("3df54690-e54d-c609-97a4-c67dd07581ee", {'success': {}} );
...

Am I doing something wrong, or is it not possible to pass a future as payload to a round trip?

Thanks in advance,

Antonio Salazar Cardozo

unread,
Mar 26, 2016, 12:50:51 PM3/26/16
to Lift
Currently round-trips don't directly support futures; you can, however,
wrap the Scala Future with a Stream instead—i.e., the Future would
map to a 1-item Stream, which item will become available when the
Future completes.

You can also implement your own RoundTripHandlerFunc, which gives
you a bit more control over things. It's basically the thing you pass as the
right hand side of "save" ->. It takes itself as a second parameter, so that
you can deal with it accordingly. A quick-and-dirty implementation for this
case:

You can also implement your own handler for round-trips by taking
a second parameter of type RoundTripHandlerFunc, which will let you
send data arbitrarily and send a message when things are done or
when something has failed. A quick-and-dirty example for this case:

  def doSave(item: JValue, roundTrip: RoundTripHandlerFunc): Unit = {
    val future = getFutureFromSlick(item)
    future.onSuccess {
      case slickItem: <TYPE> =>
        roundTrip.send(<JValue or JsCmd or JsExp>)
        roundTrip.done()
    }
    future.onFailure {
      case thingie: Exception =>
        roundTrip.failure(thingie.getMessage())
        roundTrip.done() // might not be needed, not 100% sure
    }
  }

Disclaimer: don't think I've tried my own RoundTripHandlerFunc before,
so things may not work exactly right above.
Thanks,
Antonio

Andreas Alexelis

unread,
Mar 26, 2016, 6:14:41 PM3/26/16
to Lift
Hi Antonio,
thank you so much for your helpful response.

I have already implemented Future as 1-item Stream and it seems to work ok so far. I will also give a quick try to the implementation you suggest and see how it behaves.

Thanks once again,

Antonio Salazar Cardozo

unread,
Mar 27, 2016, 11:02:33 PM3/27/16
to Lift
Awesome, glad that was helpful! Let us know which one you end up
choosing and why if you can; it could help others with the same issue
make the appropriate decision :)
Thanks,
Antonio

Andreas Alexelis

unread,
Apr 7, 2016, 12:13:31 PM4/7/16
to Lift
Hi once again,

I finally decided to go with the option you suggested, I will write at some later timing about it.
Now I have another question relating to this:

When I have a problem/exception at backend, I send a failure to the client. I would like to catch it and do something sensible according to the case of the failure but I do not know exactly how to go about it. I can see the failure received at the client in the server response, and I am looking for a way to catch it. Searching in this mailing list, I found out that client side cometFailureFunc is being called ( I debugged it and confirmed that this is indeed the case) but I don't know what is the proper way to override this function in order to be able to apply custom functionality.

Is this the correct direction to go? Any pointers on how I should go about it?
Thanks in advance,

Antonio Salazar Cardozo

unread,
Apr 7, 2016, 3:03:42 PM4/7/16
to Lift
Is that `lift_cometError`? If so, on the client you can do:

liftComet.lift_cometError = function(error) {
  // do what you want with the error
}

If it's `lift_handlerFailureFunc`, that's a different thing.

In general, I'd suggest that if there's an issue at the backend,
you send the client an error message in the form of a function
call or event.

What code do you use to generate your failure response?
Thanks,
Antonio

Andreas Alexelis

unread,
Apr 12, 2016, 10:50:56 AM4/12/16
to Lift
Hi Antonio,

thank you so much for your prompt and kind reply helping me with this.

Basically what I want to do is give some sensible feedback to the client regarding
problems that have happened in the backend. (Also as an extension of this, it would
be nice if I could also give feedback about comet problems client side, ex. a warning
notice saying "Seems that the server is not reachable right now" after, say 3 consecutive
time outs)

I have gobbled up a simple example in the github repository below:

It is a simple case of a round trip comet, that has just received a failure from, say a db rollback or something. 
Since I am using round trips, the comet instance is not readily available
in the snippet, so that one could set the notification as per usual.
So, when I pass the future failure down stream, I am looking for a way to catch the failure JSON
message at the client side. If I understood what you said correctly, are you suggesting to send
a function call instead of JSON in this case?

Thanks once again for your help.

Antonio Salazar Cardozo

unread,
Apr 13, 2016, 9:00:32 AM4/13/16
to Lift
Oh wait, if you're using round-trips those already use events. Your client-side
`fail` callback will be invoked:

window.backend.test(item)
  .then(function(item) {
    // success
  })
  .fail(function(failure) {
    // failure
  })

`failure` is whatever you passed the `failure` method on the server, JSON-encoded,
if I remember correctly.
Thanks,
Antonio

Andreas Alexelis

unread,
Apr 13, 2016, 10:56:48 AM4/13/16
to Lift
Antonio, thanks a lot!!!

this pretty much did it.
(I had it coded wrong, I thought that for promises you have to pass 2 callbacks to the .then promise, like xxx.then(successCallback, rejectCallback), instead of using fail.)
Now all I need to do is render the message in lift:Msgs from client side, to present it to the user in a uniform way with the other server side notifications.

Regarding doing the same thing with client side events, is it possible to achieve something similar when, say, comet timesout because server is unreachable?

Thanks,

Antonio Salazar Cardozo

unread,
Apr 13, 2016, 2:08:45 PM4/13/16
to Lift
Server unreachable in Lift 3 is a matter of configuring the LiftRules.ajaxDefaultFailure
setup to dispatch an event or do whatever you want, and then handling that on
the client. Let me know if you need more clarity there—basically that's just the code
that will be run when any AJAX request fails to reach the server, including regular
AJAX and comet requests.
Thanks,
Antonio
Reply all
Reply to author
Forward
0 new messages