-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ruby EventMachine Handler callback API #4630
Comments
Nevermind, |
Thanks for the suggestion. Tagging as a ReQL proposal since it's an API change and scheduling it for 2.2-polish so we can discuss it. |
Also, it would be useful if the ruby driver could support async run() without requiring eventmachine. Or just support Fibers (e.g. switch the regular condition variable used in |
@nviennot -- could you elaborate a little more on the fiber support? I confess I've never really used them. |
We shouldn't try to support all the different I/O flavors the user would want. Practically, I would rename def async_run(query, options, handler=SyncHandler.new)
...schedule query to run...
return handler
end
def run(query, options, handler=SyncHandler.new)
async_run(query, options, handler).wait
end Support we have a Handler interface defined as such: # Handler interface
class Handler
# For simplicity, I'm assuming we can only get back a single value from the
# database, excluding streams, so we don't have to deal with cursors in the
# following code.
def on_value(val)
# called from the RethinkDB thread
end
def on_error(err)
# called from the RethinkDB thread
end
def wait
# not a callback, but a way to block until we have some values.
# This is called by the synchronous version of run().
# It should return the received value, or raise received errors.
# Just like futures/promises.
end
end To provide the original behavior of class SyncHandler < Handler
def initialize
@mutex = Mutex.new
@cond = ConditionVariable.new
end
def on value(val)
@mutex.synchronize do
@value = val
@cond.signal
end
end
def on error(err)
@mutex.synchronize do
@error = err
@cond.signal
end
end
def wait
@mutex.synchronize do
@cond.wait(@mutex)
end
raise @error if @error
return @value
end
end The user could implement such Handler when using EventMachine (This could be provided by the RethinkDB driver as well): class EventMachineHandler < Handler
def initialize(success_cb, error_cb)
@success_cb = success_cb
@error_cb = error_cb
end
def on value(val)
EM.schedule { @success_cb.call(val) }
end
def on error(err)
EM.schedule { @error_cb.call(err) }
end
def wait
raise NotImplementedError
end
end Now with EventMachine and em-synchony (uses Fibers): class EventMachineSyncHandler < Handler
def initialize
@ready = EventMachine::DefaultDeferrable.new
end
def on value(val)
@ready.succeed(val)
end
def on error(err)
@ready.succeed(err)
end
def wait
value = EM::Synchrony.sync(@ready)
raise value if value.is_a?(Exception)
value
end
end The driver should not worry about what the user wants in terms of blocking handler1 = query.async_run()
handler2 = query.async_run()
value1 = handler1.wait
value2 = handler2.wait |
I think this is really nice. We could keep the current interface intact as a thin layer on top of this API, and allow for easy extensibility for users who want to use a different async method. @mlucy have you had a chance to check if this would work as a replacement for how our |
Unfortunately we didn't end up properly discussing this in the 2.2 ReQL discussion period. |
Can we bump this issue? The dependency on EM is really awkward especially as EM does not fit well in the Ruby ecosystem and has fallen out of favor in the community for that reason. Big frameworks like RoR actively avoid EM. Would you accept a PR for this? Does the team approve of the name |
@tinco We'll look into it for RethinkDB 2.4 (the next major release). |
I like @nviennot's proposal for a generic abstraction over different types of asynchronous behavior. Two things I'd change, though:
I think we should continue to support the existing @tinco -- since this is an API change it needs to go through the ReQL proposal process for 2.4 in case anyone has objections. The 2.4 proposal process should be happening pretty soon though, and we'd be happy to accept a pull request. We have a lot of tests using |
I read over everything above. Here's a slight variant of the proposal that I think does what we want:
|
Sounds great, would be excellent if we could get it in together with the Rails 5.0 release. A well timed blog post on Rails 5.0 support would maybe get RethinkDB some exposure :) |
@mlucy This interface sounds a bit technical to me (e.g. it's not obvious what the purpose of the block passed to |
@tinco Do you know if there's an ETA for Rails 5.0? |
@danielmewes they usually do 2rc's with about a month between them, and the full release about a week after the 2nd rc, so if history is any indicator it could be within a week or two. The interface will only be used by library implementors so I don't think it being a little bit technical should be an issue. I would offer to help with the implementation but unfortunately I'm moving next wednesday so I have a super busy weekend ahead of me :) |
Marking settled on the proposal from this comment #4630 (comment) |
Hi :)
I was trying to abort a ongoing query from an em_run() call, but the only way I found was to save the
caller
variable (which is aQueryHandle
) from any of these callbacks:rethinkdb/drivers/ruby/lib/net.rb
Lines 63 to 92 in f1f60df
close()
on thequery_handle
.This might not be ideal, because these callbacks might not have had the time to be called, but
EM.next_tick()
did. Maybe an EM callback would want to close the query_handle already.Here's what I suggest we do:
caller
arguments from theHandler
callbacks.on_dispatch(query_handle)
that would be called right around here:rethinkdb/drivers/ruby/lib/net.rb
Line 530 in f1f60df
This way we don't need a response from the server to terminate an ongoing query.
I've made NoBrainer compatible with EventMachine through the use of Fibers (so the code is still written in an asynchronous manner). If you are curious about how I use the
Handler
callbacks, check it out here: https://github.com/nviennot/nobrainer/blob/master/lib/no_brainer/query_runner/em_driver.rbFurther, I've written a self-contained Goliath server to demonstrate the usefulness of the Fiber abstraction: https://gist.github.com/nviennot/67a0795db7ccad973885
Maybe we could add this as a real-time tutorial to complement http://www.rethinkdb.com/docs/rails/
The text was updated successfully, but these errors were encountered: