What is the correct way to execute requests in a correct order?

16 views
Skip to first unread message

Man Vuong

unread,
Oct 21, 2014, 2:40:43 AM10/21/14
to rest...@googlegroups.com
Hi,

I had some problem with requests queuing in RestFirebase, but I think it should be a question for RestCore also, so I post it here.
For instance, I use Firebase in my simple chat service, here is the logic when user leave a room:
  create leaving message -> remove user-rooms node -> remove room/users nodeEnter

I need to execute these requests in a correct order, instead of letting them run concurrently, so I tried something like this:

client = RestFirebase.new site: 'https://SampleChat.firebaseIO-demo.com/'


# Pseudo code when user's leaving a room
client
.put('chat-messages/1', {text: 'Tom left the room'}) {
  client
.delete('user-rooms/1/2') {
    client
.delete('rooms/1/users/1')
 
}
}

It worked, but I wonder if we have a better approach to avoid the callback-hell and flatten the callback pyramid? Like this:

client.put('chat-messages/1', {text: 'Tom left the room'}).then {
  client
.delete('user-rooms/1/2')
}.then {
  client
.delete('rooms/1/users/1')
}




 

Man Vuong

unread,
Oct 21, 2014, 2:51:15 AM10/21/14
to rest...@googlegroups.com
Sorry for some typos.

Lin Jen-Shin (godfat)

unread,
Oct 21, 2014, 9:28:08 AM10/21/14
to rest...@googlegroups.com
Hi,
Interesting, I never really thought of this before. I thought if
we don't want callbacks and want sequential calls, we could simply
block there.

For example, we could also do this:

client.put('chat-messages/1', {text: 'Tom left the room'}).tap{}
client.delete('user-rooms/1/2').tap{}
client.delete('rooms/1/users/1').tap{}

Here `tap{}` would force the request to be done, effectively making
those 3 calls sequential. But we probably don't really want to block
here? Then maybe a combination of them:

client.put('chat-messages/1', {text: 'Tom left the room'}) do
client.delete('user-rooms/1/2').tap{}
client.delete('rooms/1/users/1').tap{}
end

Does this make sense? This way, the first request is not blocking,
but the rests which would be called in another thread would be blocking.
At least they are not blocking the main thread. This would somehow
work like your example of using `then`, with slightly different API.

Actually, there's `then` method but it's not working like that,
and the only place which I am aware of and use it is from Github client:

https://github.com/godfat/rest-more/blob/rest-more-3.3.1/lib/rest-core/client/github.rb#L62-L78

I am not going to explain all the details here (unless anyone is interested),
but in short, it's for chaining promises and returning the chained promise.
To use that in this example, it would look like the original callback hell
with much more keystrokes, so it's not something we're looking for here.

The main difference from your example is, `then` is chaining on the original
promise, not the next one we'll expect here. If we chain them like your
example, the two subsequent requests would be made *concurrently*, and
that's not we're expecting here.


Please let me know if a callback with the others calling with `tap{}` making
sense to you. We could improve the API if that just looks weird, though I
don't feel if your example API would be possible to implement. The problem
is that, we don't know which requests we made in the callback. Sure we could
take the last value as the next request, but I feel it's too restricting and
could be unexpected. (suppose we make a bunch of requests in the first
callback, what should happen?)

Man Vuong

unread,
Oct 21, 2014, 1:26:45 PM10/21/14
to rest...@googlegroups.com
I see. Thank you. I'm good with the callback approach. `tap` is good also, but it will block the thread, and the code will look weird for people who don't understand its purpose ;)

Lin Jen-Shin (godfat)

unread,
Oct 22, 2014, 12:57:57 PM10/22/14
to rest...@googlegroups.com
On Wed, Oct 22, 2014 at 1:26 AM, Man Vuong <thanh...@gmail.com> wrote:
> I see. Thank you. I'm good with the callback approach. `tap` is good also,
> but it will block the thread, and the code will look weird for people who
> don't understand its purpose ;)

No problem.

I agree that `tap{}` looks quite weird and can't really speak for its
purpose here, but I also hesitate to introduce a method for this because
we're using BasicObject as a proxy here, adding any method could potentially
be conflicting with the original object.

I always hope something like this could be merged:
https://bugs.ruby-lang.org/issues/6373

Looks like it's merged 3 months ago, with `itself`.

So maybe in the future we could use `client.get(something).itself` to
force loading the response (thus blocking). It might still look a bit
weird, but I think it would be much better with `tap{}` especially
having that weird `{}`.

Also, I am also thinking that if we should stop using BasicObject to
proxy the response. There's a discussion going on Github:
https://github.com/godfat/rest-core/issues/9

This would definitely be a fairly large breaking change though, basically
breaking everything...
Reply all
Reply to author
Forward
0 new messages