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