lib/zk/client/threaded.rb in zk-1.0.0 vs lib/zk/client/threaded.rb in zk-1.1.0
- old
+ new
@@ -13,27 +13,15 @@
# threads are delivering events. The documentation for 0.9.0 was incorrect
# in stating the number of threads used to deliver events. There was one,
# unconfigurable, event dispatch thread. In 1.0 the number of event
# delivery threads is configurable, but still defaults to 1.
#
- # The configurability is intended to allow users to easily dispatch events to
- # event handlers that will perform (application specific) work. Be aware,
- # the default will give you the guarantee that only one event will be delivered
- # at a time. The advantage to this is that you can be sure that no event will
- # be delivered "behind your back" while you're in an event handler. If you're
- # comfortable with dealing with threads and concurrency, then feel free to
- # set the `:threadpool_size` option to the constructor to a value you feel is
- # correct for your app.
- #
# If you use the threadpool/event callbacks to perform work, you may be
# interested in registering an `on_exception` callback that will receive
# all exceptions that occur on the threadpool that are not handled (i.e.
# that bubble up to top of a block).
#
- # It is recommended that you not run any possibly long-running work on the
- # event threadpool, as `close!` will attempt to shutdown the threadpool, and
- # **WILL NOT WAIT FOREVER**. (TODO: more on this)
#
# @example Register on_connected callback.
#
# # the nice thing about this pattern is that in the case of a call to #reopen
# # all your watches will be re-established
@@ -65,27 +53,58 @@
# is planned.
#
# @note The documentation for 0.9.0 was incorrect in stating the number
# of threads used to deliver events. There was one, unconfigurable,
# event dispatch thread. In 1.0 the number of event delivery threads is
- # configurable, but still defaults to 1. (The Management apologizes for
- # any confusion this may have caused).
+ # configurable, but still defaults to 1 and users are discouraged from
+ # adjusting the value due to the complexity this introduces. In 1.1
+ # there is a better option for achieving higher concurrency (see the
+ # `:thread` option)
#
+ # The Management apologizes for any confusion this may have caused.
+ #
+ # @since __1.1__: Instead of adjusting the threadpool, users are _strongly_ encouraged
+ # to use the `:thread => :per_callback` option to increase the
+ # parallelism of event delivery safely and sanely. Please see
+ # [this wiki article](https://github.com/slyphon/zk/wiki/EventDeliveryModel) for more
+ # information and a demonstration.
+ #
# @param [String] host (see ZK::Client::Base#initialize)
#
# @option opts [true,false] :reconnect (true) if true, we will register
# the equivalent of `on_session_expired { zk.reopen }` so that in the
# case of an expired session, we will keep trying to reestablish the
# connection.
#
- # @option opts [Fixnum] :threadpool_size (1) the size of the threadpool that
- # should be used to deliver events. As of 1.0, this is the number of
- # event delivery threads and controls the amount of concurrency in your
- # app if you're doing work in the event callbacks.
+ # @option opts [:single,:per_callback] :thread (:single) choose your event
+ # delivery model:
#
+ # * `:single`: There is one thread, and only one callback is called at
+ # a time. This is the default mode (for now), and will provide the most
+ # safety for your app. All events will be delivered as received, to
+ # callbacks in the order they were registered. This safety has the
+ # tradeoff that if one of your callbacks performs some action that blocks
+ # the delivery thread, you will not recieve other events until it returns.
+ # You're also limiting the concurrency of your app. This should be fine
+ # for most simple apps, and is a good choice to start with when
+ # developing your application
+ #
+ # * `:per_callback`: This option will use a new-style Actor model (inspired by
+ # [Celluloid](https://github.com/celluloid/celluloid)) that uses a
+ # per-callback queue and thread to allow for greater concurrency in
+ # your app, whille still maintaining some kind of sanity. By choosing
+ # this option your callbacks will receive events in order, and will
+ # receive only one at a time, but in parallel with other callbacks.
+ # This model has the advantage you can have all of your callbacks
+ # making progress in parallel, and if one of them happens to block,
+ # it will not affect the others.
+ #
+ # * see {https://github.com/slyphon/zk/wiki/EventDeliveryModel the wiki} for a
+ # discussion and demonstration of the effect of this setting.
+ #
# @option opts [Fixnum] :timeout how long we will wait for the connection
- # to be established. If timeout is nil, we will wait forever *use
+ # to be established. If timeout is nil, we will wait forever: *use
# carefully*.
#
# @yield [self] calls the block with the new instance after the event
# handler and threadpool have been set up, but before any connections
# have been made. This allows the client to register watchers for
@@ -99,10 +118,10 @@
tp_size = opts.fetch(:threadpool_size, DEFAULT_THREADPOOL_SIZE)
@threadpool = Threadpool.new(tp_size)
@session_timeout = opts.fetch(:timeout, DEFAULT_TIMEOUT) # maybe move this into superclass?
- @event_handler = EventHandler.new(self)
+ @event_handler = EventHandler.new(self, opts)
@reconnect = opts.fetch(:reconnect, true)
@mutex = Mutex.new