zk 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.dotfiles/ctags_paths +1 -0
- data/.dotfiles/rspec-logging +2 -2
- data/.gitignore +1 -0
- data/Gemfile +9 -3
- data/Guardfile +36 -0
- data/README.markdown +21 -18
- data/RELEASES.markdown +10 -0
- data/Rakefile +1 -1
- data/lib/zk.rb +28 -21
- data/lib/zk/client/threaded.rb +107 -17
- data/lib/zk/client/unixisms.rb +1 -41
- data/lib/zk/core_ext.rb +28 -0
- data/lib/zk/election.rb +14 -3
- data/lib/zk/event_handler.rb +36 -37
- data/lib/zk/event_handler_subscription/actor.rb +37 -2
- data/lib/zk/event_handler_subscription/base.rb +9 -0
- data/lib/zk/exceptions.rb +5 -0
- data/lib/zk/fork_hook.rb +112 -0
- data/lib/zk/install_fork_hooks.rb +37 -0
- data/lib/zk/locker/exclusive_locker.rb +14 -10
- data/lib/zk/locker/locker_base.rb +43 -26
- data/lib/zk/locker/shared_locker.rb +9 -5
- data/lib/zk/logging.rb +29 -7
- data/lib/zk/node_deletion_watcher.rb +167 -0
- data/lib/zk/pool.rb +14 -4
- data/lib/zk/subscription.rb +15 -34
- data/lib/zk/threaded_callback.rb +113 -29
- data/lib/zk/threadpool.rb +136 -40
- data/lib/zk/version.rb +1 -1
- data/spec/logging_progress_bar_formatter.rb +12 -0
- data/spec/shared/client_contexts.rb +13 -1
- data/spec/shared/client_examples.rb +3 -1
- data/spec/spec_helper.rb +28 -3
- data/spec/support/client_forker.rb +49 -8
- data/spec/support/latch.rb +1 -19
- data/spec/support/logging.rb +26 -10
- data/spec/support/wait_watchers.rb +2 -2
- data/spec/zk/00_forked_client_integration_spec.rb +1 -1
- data/spec/zk/client_spec.rb +11 -2
- data/spec/zk/election_spec.rb +21 -7
- data/spec/zk/locker_spec.rb +42 -22
- data/spec/zk/node_deletion_watcher_spec.rb +69 -0
- data/spec/zk/pool_spec.rb +32 -18
- data/spec/zk/threaded_callback_spec.rb +78 -0
- data/spec/zk/threadpool_spec.rb +52 -0
- data/spec/zk/watch_spec.rb +4 -0
- data/zk.gemspec +2 -1
- metadata +36 -10
- data/spec/support/logging_progress_bar_formatter.rb +0 -14
@@ -0,0 +1 @@
|
|
1
|
+
~/vendor/ruby/*.{c,h}
|
data/.dotfiles/rspec-logging
CHANGED
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -8,11 +8,10 @@ source :rubygems
|
|
8
8
|
# keep closer track of this stuff to make bisecting easier and travis more
|
9
9
|
# accurate
|
10
10
|
|
11
|
-
# git 'git://github.com/slyphon/zookeeper.git', :tag => 'dev/zk/
|
12
|
-
# gem 'zookeeper', '~> 1.
|
11
|
+
# git 'git://github.com/slyphon/zookeeper.git', :tag => 'dev/zk/00006' do
|
12
|
+
# gem 'zookeeper', '~> 1.1.0'
|
13
13
|
# end
|
14
14
|
|
15
|
-
|
16
15
|
gem 'rake', :group => [:development, :test]
|
17
16
|
gem 'pry', :group => [:development]
|
18
17
|
|
@@ -28,6 +27,13 @@ platform :mri_19 do
|
|
28
27
|
gem 'simplecov', :group => :coverage, :require => false
|
29
28
|
end
|
30
29
|
|
30
|
+
group :development do
|
31
|
+
gem 'guard', :require => false
|
32
|
+
gem 'guard-rspec', :require => false
|
33
|
+
gem 'guard-shell', :require => false
|
34
|
+
gem 'guard-bundler', :require => false
|
35
|
+
end
|
36
|
+
|
31
37
|
group :test do
|
32
38
|
gem 'rspec', '~> 2.8.0'
|
33
39
|
gem 'flexmock', '~> 0.8.10'
|
data/Guardfile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
dot_rspec_path = File.expand_path('../.rspec', __FILE__)
|
5
|
+
|
6
|
+
rspec_options = File.open('.rspec', &:readlines).map(&:chomp).reject{|n| n =~ /\A(#|\Z)/}
|
7
|
+
|
8
|
+
guard 'bundler' do
|
9
|
+
watch 'Gemfile'
|
10
|
+
watch /\A.+\.gemspec\Z/
|
11
|
+
end
|
12
|
+
|
13
|
+
guard 'rspec', :version => 2 do
|
14
|
+
watch(%r{^spec/.+_spec\.rb$})
|
15
|
+
|
16
|
+
watch(%r%^spec/support/client_forker.rb$%) { 'spec/zk/00_forked_client_integration_spec.rb' }
|
17
|
+
|
18
|
+
watch(%r{^lib/(.+)\.rb$}) do |m|
|
19
|
+
case m[1]
|
20
|
+
when %r{^zk/event_handler$}
|
21
|
+
"spec/zk/watch_spec.rb"
|
22
|
+
when %r{^zk/client/threaded.rb$}
|
23
|
+
["spec/zk/client_spec.rb", "spec/zk/zookeeper_spec.rb"]
|
24
|
+
when %r{^zk/locker/}
|
25
|
+
"spec/zk/locker_spec.rb"
|
26
|
+
when %r{^zk\.rb$}
|
27
|
+
'spec' # run all tests
|
28
|
+
else
|
29
|
+
"spec/#{m[1]}_spec.rb"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
watch('spec/spec_helper.rb') { "spec" }
|
34
|
+
end
|
35
|
+
|
36
|
+
|
data/README.markdown
CHANGED
@@ -65,6 +65,27 @@ In addition to all of that, I would like to think that the public API the ZK::Cl
|
|
65
65
|
[zk-eventmachine]: https://github.com/slyphon/zk-eventmachine
|
66
66
|
|
67
67
|
## NEWS ##
|
68
|
+
### v1.5.0 ###
|
69
|
+
|
70
|
+
Ok, now seriously this time. I think all of the forking issues are done.
|
71
|
+
|
72
|
+
* Implemented a 'stop the world' feature to ensure safety when forking. All threads are stopped, but state is preserved. `fork()` can then be called safely, and after fork returns, all threads will be restarted in the parent, and the connection will be torn down and reopened in the child.
|
73
|
+
|
74
|
+
* The easiest, and supported, way of doing this is now to call `ZK.install_fork_hook` after requiring zk. This will install an `alias_method_chain` style hook around the `Kernel.fork` method, which handles pausing all clients in the parent, calling fork, then resuming in the parent and reconnecting in the child. If you're using ZK in resque, I *highly* recommend using this approach, as it will give the most consistent results.
|
75
|
+
|
76
|
+
In your app that requires an open ZK instance and `fork()`:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
|
80
|
+
require 'zk'
|
81
|
+
ZK.install_fork_hook
|
82
|
+
|
83
|
+
```
|
84
|
+
|
85
|
+
Then use fork as you normally would.
|
86
|
+
|
87
|
+
* Logging is now off by default, but we now use the excellent, can't-recommend-it-enough, [logging](https://github.com/TwP/logging) gem. If you want to tap into the ZK logs, you can assign a stdlib compliant logger to `ZK.logger` and that will be used. Otherwise, you can use the Logging framework's controls. All ZK logs are consolidated under the 'ZK' logger instance.
|
88
|
+
|
68
89
|
|
69
90
|
### v1.4.1 ###
|
70
91
|
|
@@ -105,24 +126,6 @@ Phusion Passenger and Unicorn users are encouraged to upgrade!
|
|
105
126
|
|
106
127
|
* See the fork-handling documentation [on the wiki](http://github.com/slyphon/zk/wiki/Forking).
|
107
128
|
|
108
|
-
### v1.2.0 ###
|
109
|
-
|
110
|
-
You are __STRONGLY ENCOURAGED__ to go and look at the [CHANGELOG](http://git.io/tPbNBw) from the zookeeper 1.0.0 release
|
111
|
-
|
112
|
-
* NOTICE: This release uses the 1.0 release of the zookeeper gem, which has had a MAJOR REFACTORING of its namespaces. Included in that zookeeper release is a compatibility layer that should ease the transition, but any references to Zookeeper\* heirarchy should be changed.
|
113
|
-
|
114
|
-
* Refactoring related to the zokeeper gem, use all the new names internally now.
|
115
|
-
|
116
|
-
* Create a new Subscription class that will be used as the basis for all subscription-type things.
|
117
|
-
|
118
|
-
* Add new Locker features!
|
119
|
-
* `LockerBase#assert!` - will raise an exception if the lock is not held. This check is not only for local in-memory "are we locked?" state, but will check the connection state and re-run the algorithmic tests that determine if a given Locker implementation actually has the lock.
|
120
|
-
* `LockerBase#acquirable?` - an advisory method that checks if any condition would prevent the receiver from acquiring the lock.
|
121
|
-
|
122
|
-
* Deprecation of the `lock!` and `unlock!` methods. These may change to be exception-raising in a future relase, so document and refactor that `lock` and `unlock` are the way to go.
|
123
|
-
|
124
|
-
* Fixed a race condition in `event_catcher_spec.rb` that would cause 100% cpu usage and hang.
|
125
|
-
|
126
129
|
|
127
130
|
## Caveats
|
128
131
|
|
data/RELEASES.markdown
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
This file notes feature differences and bugfixes contained between releases.
|
2
2
|
|
3
|
+
### v1.5.0 ###
|
4
|
+
|
5
|
+
Ok, now seriously this time. I think all of the forking issues are done.
|
6
|
+
|
7
|
+
* Implemented a 'stop the world' feature to ensure safety when forking. All threads are stopped, but state is preserved. `fork()` can then be called safely, and after fork returns, all threads will be restarted in the parent, and the connection will be torn down and reopened in the child.
|
8
|
+
|
9
|
+
* The easiest, and supported, way of doing this is now to call `ZK.install_fork_hook` after requiring zk. This will install an `alias_method_chain` style hook around the `Kernel.fork` method, which handles pausing all clients in the parent, calling fork, then resuming in the parent and reconnecting in the child. If you're using ZK in resque, I *highly* recommend using this approach, as it will give the most consistent results.
|
10
|
+
|
11
|
+
* Logging is now off by default, and uses the excellent, can't-recommend-it-enough, [logging](https://github.com/TwP/logging) gem. If you want to tap into the ZK logs, you can assign a stdlib compliant logger to `ZK.logger` and that will be used. Otherwise, you can use the Logging framework's controls. All ZK logs are consolidated under the 'ZK' logger instance.
|
12
|
+
|
3
13
|
### v1.4.1 ###
|
4
14
|
|
5
15
|
* True fork safety! The `zookeeper` at 1.1.0 is finally fork-safe. You can now use ZK in whatever forking library you want. Just remember to call `#reopen` on your client instance in the child process before attempting any opersations.
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ if File.exists?(release_ops_path)
|
|
8
8
|
require File.join(release_ops_path, 'releaseops')
|
9
9
|
|
10
10
|
# sets up the multi-ruby zk:test_all rake tasks
|
11
|
-
ReleaseOps::TestTasks.define_for(*%w[1.8.7 1.9.2 jruby
|
11
|
+
ReleaseOps::TestTasks.define_for(*%w[1.8.7 1.9.2 jruby ree 1.9.3])
|
12
12
|
|
13
13
|
# sets up the task :default => 'spec:run' and defines a simple
|
14
14
|
# "run the specs with the current rvm profile" task
|
data/lib/zk.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'logging'
|
4
4
|
require 'zookeeper'
|
5
5
|
|
6
6
|
# XXX: after 1.0 we'll need this
|
@@ -12,21 +12,28 @@ require 'monitor'
|
|
12
12
|
require 'set'
|
13
13
|
require 'time'
|
14
14
|
require 'date'
|
15
|
+
require 'weakref'
|
15
16
|
|
16
17
|
module ZK
|
18
|
+
# just like stdlib Monitor but provides the SAME API AS MUTEX, FFS!
|
19
|
+
# @private
|
20
|
+
class Monitor < Zookeeper::Monitor
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
require 'zk/core_ext'
|
20
|
-
require 'zk/logging'
|
21
25
|
require 'zk/exceptions'
|
22
26
|
require 'zk/extensions'
|
27
|
+
require 'zk/logging'
|
23
28
|
require 'zk/event'
|
24
29
|
require 'zk/stat'
|
25
30
|
require 'zk/subscription'
|
31
|
+
require 'zk/fork_hook'
|
26
32
|
require 'zk/threadpool'
|
27
33
|
require 'zk/threaded_callback'
|
28
34
|
require 'zk/event_handler_subscription'
|
29
35
|
require 'zk/event_handler'
|
36
|
+
require 'zk/node_deletion_watcher'
|
30
37
|
require 'zk/message_queue'
|
31
38
|
require 'zk/locker'
|
32
39
|
require 'zk/election'
|
@@ -46,9 +53,7 @@ module ZK
|
|
46
53
|
KILL_TOKEN = Object.new
|
47
54
|
end
|
48
55
|
|
49
|
-
unless
|
50
|
-
@logger = Logger.new($stderr).tap { |n| n.level = ENV['ZK_DEBUG'] ? Logger::DEBUG : Logger::ERROR }
|
51
|
-
end
|
56
|
+
@@logger = nil unless defined? @@logger
|
52
57
|
|
53
58
|
@default_host = 'localhost' unless @default_host
|
54
59
|
@default_port = 2181 unless @default_port
|
@@ -65,14 +70,6 @@ module ZK
|
|
65
70
|
attr_accessor :default_chroot
|
66
71
|
end
|
67
72
|
|
68
|
-
# @private
|
69
|
-
def self.default_connection_string
|
70
|
-
"#{default_host}:#{default_port}".tap do |str|
|
71
|
-
# XXX: this is seriously blech
|
72
|
-
str.replace(File.join(str, default_chroot)) if default_chroot != ''
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
73
|
# The logger used by the ZK library. uses a Logger stderr with Logger::ERROR
|
77
74
|
# level. The only thing that should ever be logged are exceptions that are
|
78
75
|
# swallowed by background threads.
|
@@ -81,12 +78,20 @@ module ZK
|
|
81
78
|
# implements the stdllb Logger API.
|
82
79
|
#
|
83
80
|
def self.logger
|
84
|
-
|
81
|
+
@@logger
|
85
82
|
end
|
86
83
|
|
87
|
-
#
|
88
|
-
def self.logger=(
|
89
|
-
|
84
|
+
# set the ZK logger instance
|
85
|
+
def self.logger=(log)
|
86
|
+
@@logger = log
|
87
|
+
end
|
88
|
+
|
89
|
+
# @private
|
90
|
+
def self.default_connection_string
|
91
|
+
"#{default_host}:#{default_port}".tap do |str|
|
92
|
+
# XXX: this is seriously blech
|
93
|
+
str.replace(File.join(str, default_chroot)) if default_chroot != ''
|
94
|
+
end
|
90
95
|
end
|
91
96
|
|
92
97
|
# Create a new ZK::Client instance. If no arguments are given, the default
|
@@ -205,9 +210,10 @@ module ZK
|
|
205
210
|
cnx = new(*args)
|
206
211
|
yield cnx
|
207
212
|
ensure
|
208
|
-
|
209
|
-
|
210
|
-
|
213
|
+
if cnx
|
214
|
+
cnx.close!
|
215
|
+
Thread.pass until cnx.closed?
|
216
|
+
end
|
211
217
|
end
|
212
218
|
|
213
219
|
# creates a new ZK::Pool::Bounded with the default options.
|
@@ -292,7 +298,6 @@ module ZK
|
|
292
298
|
open(host) do |zk| # do path stuff with the virgin connection
|
293
299
|
unless zk.exists?(chroot_path) # someting must be done
|
294
300
|
if chroot_opt == :create # here, let me...
|
295
|
-
logger.debug { "creating chroot path #{chroot_path}" }
|
296
301
|
zk.mkdir_p(chroot_path) # ...get that for you
|
297
302
|
else # careful with that axe
|
298
303
|
raise Exceptions::ChrootPathDoesNotExistError.new(host, chroot_path) # ...eugene
|
@@ -304,3 +309,5 @@ module ZK
|
|
304
309
|
end
|
305
310
|
end
|
306
311
|
|
312
|
+
ZK::Logging.set_default
|
313
|
+
|
data/lib/zk/client/threaded.rb
CHANGED
@@ -140,8 +140,15 @@ module ZK
|
|
140
140
|
@reconnect = opts.fetch(:reconnect, true)
|
141
141
|
|
142
142
|
@mutex = Monitor.new
|
143
|
+
@cond = @mutex.new_cond
|
143
144
|
|
144
|
-
@
|
145
|
+
@cli_state = :running # this is to distinguish between *our* state and the underlying connection state
|
146
|
+
|
147
|
+
@fork_subs = [
|
148
|
+
ForkHook.prepare_for_fork(method(:pause_before_fork_in_parent)),
|
149
|
+
ForkHook.after_fork_in_parent(method(:resume_after_fork_in_parent)),
|
150
|
+
ForkHook.after_fork_in_child(method(:reopen)),
|
151
|
+
]
|
145
152
|
|
146
153
|
yield self if block_given?
|
147
154
|
|
@@ -169,25 +176,69 @@ module ZK
|
|
169
176
|
# ok, just to sanity check here
|
170
177
|
raise "[BUG] we hit the fork-reopening code in JRuby!!" if defined?(::JRUBY_VERSION)
|
171
178
|
|
172
|
-
logger.debug { "
|
179
|
+
logger.debug { "reopening everything, fork detected!" }
|
173
180
|
|
174
181
|
@mutex = Monitor.new
|
175
|
-
@threadpool.reopen_after_fork! # prune dead threadpool threads after a fork()
|
176
|
-
@event_handler.reopen_after_fork!
|
177
182
|
@pid = Process.pid
|
183
|
+
@cli_state = :running # reset state to running if we were paused
|
178
184
|
|
179
185
|
old_cnx, @cnx = @cnx, nil
|
180
186
|
old_cnx.close! if old_cnx # && !old_cnx.closed?
|
187
|
+
|
188
|
+
@mutex.synchronize do
|
189
|
+
# it's important that we're holding the lock, as access to 'cnx' is
|
190
|
+
# synchronized, and we want to avoid a race where event handlers
|
191
|
+
# might see a nil connection. I've seen this exception occur *once*
|
192
|
+
# so it's pretty rare (it was on 1.8.7 too), but just to be double
|
193
|
+
# extra paranoid
|
194
|
+
|
195
|
+
@event_handler.reopen_after_fork!
|
196
|
+
@threadpool.reopen_after_fork! # prune dead threadpool threads after a fork()
|
197
|
+
|
198
|
+
connect
|
199
|
+
end
|
181
200
|
else
|
182
|
-
|
183
|
-
|
201
|
+
@mutex.synchronize do
|
202
|
+
if @cli_state == :paused
|
203
|
+
# XXX: what to do in this case? does it matter?
|
204
|
+
end
|
205
|
+
|
206
|
+
logger.debug { "reopening, no fork detected" }
|
207
|
+
@cnx.reopen(timeout) # ok, we werent' forked, so just reopen
|
208
|
+
end
|
184
209
|
end
|
185
210
|
|
186
|
-
@mutex.synchronize { @close_requested = false }
|
187
|
-
connect
|
188
211
|
state
|
189
212
|
end
|
190
213
|
|
214
|
+
# Before forking, call this method to peform a "stop the world" operation on all
|
215
|
+
# objects associated with this connection. This means that this client will spin down
|
216
|
+
# and join all threads (so make sure none of your callbacks will block forever),
|
217
|
+
# and will tke no action to keep the session alive. With the default settings,
|
218
|
+
# if a ping is not received within 20 seconds, the session is considered dead
|
219
|
+
# and must be re-established so be sure to call {#resume_after_fork_in_parent}
|
220
|
+
# before that deadline, or you will have to re-establish your session.
|
221
|
+
#
|
222
|
+
# @raise [InvalidStateError] when called and not in running? state
|
223
|
+
def pause_before_fork_in_parent
|
224
|
+
@mutex.synchronize do
|
225
|
+
raise InvalidStateError, "client must be running? when you call #{__method__}" unless running?
|
226
|
+
@cli_state = :paused
|
227
|
+
end
|
228
|
+
logger.debug { "#{self.class}##{__method__}" }
|
229
|
+
[@event_handler, @threadpool, @cnx].each(&:pause_before_fork_in_parent)
|
230
|
+
end
|
231
|
+
|
232
|
+
def resume_after_fork_in_parent
|
233
|
+
@mutex.synchronize do
|
234
|
+
raise InvalidStateError, "client must be paused? when you call #{__method__}" unless paused?
|
235
|
+
@cli_state = :running
|
236
|
+
end
|
237
|
+
|
238
|
+
logger.debug { "#{self.class}##{__method__}" }
|
239
|
+
[@cnx, @event_handler, @threadpool].each(&:resume_after_fork_in_parent)
|
240
|
+
end
|
241
|
+
|
191
242
|
# (see Base#close!)
|
192
243
|
#
|
193
244
|
# @note We will make our best effort to do the right thing if you call
|
@@ -198,8 +249,9 @@ module ZK
|
|
198
249
|
#
|
199
250
|
def close!
|
200
251
|
@mutex.synchronize do
|
201
|
-
return if @
|
202
|
-
|
252
|
+
return if [:closed, :close_requested].include?(@cli_state)
|
253
|
+
# logger.debug { "moving to :close_requested state" }
|
254
|
+
@cli_state = :close_requested
|
203
255
|
end
|
204
256
|
|
205
257
|
on_tpool = on_threadpool?
|
@@ -213,18 +265,24 @@ module ZK
|
|
213
265
|
# and wait for it to exit
|
214
266
|
#
|
215
267
|
shutdown_thread = Thread.new do
|
216
|
-
@threadpool.shutdown(
|
268
|
+
@threadpool.shutdown(10)
|
217
269
|
super
|
218
|
-
end
|
219
270
|
|
220
|
-
|
271
|
+
@mutex.synchronize do
|
272
|
+
# logger.debug { "moving to :closed state" }
|
273
|
+
@cli_state = :closed
|
274
|
+
end
|
275
|
+
end
|
221
276
|
|
222
|
-
|
277
|
+
on_tpool ? shutdown_thread : shutdown_thread.join
|
223
278
|
end
|
224
279
|
|
225
280
|
# {see Base#close}
|
226
281
|
def close
|
227
282
|
super
|
283
|
+
subs, @fork_subs = @fork_subs, []
|
284
|
+
subs.each(&:unsubscribe)
|
285
|
+
nil
|
228
286
|
end
|
229
287
|
|
230
288
|
# (see Threadpool#on_threadpool?)
|
@@ -245,12 +303,13 @@ module ZK
|
|
245
303
|
return unless @reconnect
|
246
304
|
|
247
305
|
@mutex.synchronize do
|
248
|
-
unless
|
306
|
+
unless dead_or_dying? # a legitimate shutdown case
|
249
307
|
|
250
308
|
logger.error { "Got event #{event.state_name}, calling reopen(0)! things may be messed up until this works itself out!" }
|
251
309
|
|
252
310
|
# reopen(0) means that we don't want to wait for the connection
|
253
|
-
# to reach the connected state before returning
|
311
|
+
# to reach the connected state before returning as we're on the
|
312
|
+
# event thread.
|
254
313
|
reopen(0)
|
255
314
|
end
|
256
315
|
end
|
@@ -259,11 +318,42 @@ module ZK
|
|
259
318
|
logger.error { "BUG: Exception caught in raw_event_handler: #{e.to_std_format}" }
|
260
319
|
end
|
261
320
|
|
321
|
+
def closed?
|
322
|
+
return true if @mutex.synchronize { @cli_state == :closed }
|
323
|
+
super
|
324
|
+
end
|
325
|
+
|
326
|
+
# are we in running (not-paused) state?
|
327
|
+
def running?
|
328
|
+
@mutex.synchronize { @cli_state == :running }
|
329
|
+
end
|
330
|
+
|
331
|
+
# are we in paused state?
|
332
|
+
def paused?
|
333
|
+
@mutex.synchronize { @cli_state == :paused }
|
334
|
+
end
|
335
|
+
|
336
|
+
# has shutdown time arrived?
|
337
|
+
def close_requested?
|
338
|
+
@mutex.synchronize { @cli_state == :close_requested }
|
339
|
+
end
|
340
|
+
|
262
341
|
protected
|
342
|
+
# in the threaded version of the client, synchronize access around cnx
|
343
|
+
# so that callers don't wind up with a nil object when we're in the middle
|
344
|
+
# of reopening it
|
345
|
+
def cnx
|
346
|
+
@mutex.synchronize { @cnx }
|
347
|
+
end
|
348
|
+
|
263
349
|
# @private
|
264
350
|
def create_connection(*args)
|
265
351
|
::Zookeeper.new(*args)
|
266
352
|
end
|
267
|
-
|
353
|
+
|
354
|
+
def dead_or_dying?
|
355
|
+
(@cli_state == :close_requested) || (@cli_state == :closed)
|
356
|
+
end
|
357
|
+
end
|
268
358
|
end
|
269
359
|
end
|