zk 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -3
- data/README.markdown +8 -0
- data/docs/examples/events_01.rb +4 -1
- data/docs/examples/events_02.rb +5 -1
- data/lib/zk/client/base.rb +41 -7
- data/lib/zk/client/threaded.rb +44 -7
- data/lib/zk/core_ext.rb +1 -0
- data/lib/zk/election.rb +2 -1
- data/lib/zk/event_handler.rb +16 -6
- data/lib/zk/event_handler_subscription/base.rb +0 -12
- data/lib/zk/locker/locker_base.rb +6 -1
- data/lib/zk/message_queue.rb +10 -2
- data/lib/zk/subscription.rb +12 -1
- data/lib/zk/threaded_callback.rb +20 -5
- data/lib/zk/threadpool.rb +42 -11
- data/lib/zk/version.rb +1 -1
- data/lib/zk.rb +4 -1
- data/spec/informal/what-the-fork.rb +4 -1
- data/spec/shared/client_examples.rb +2 -0
- data/spec/support/event_catcher.rb +12 -1
- data/spec/support/pendings.rb +12 -0
- data/spec/zk/client_spec.rb +86 -1
- data/spec/zk/pool_spec.rb +8 -2
- data/spec/zookeeper_spec.rb +4 -1
- data/zk.gemspec +1 -2
- metadata +7 -9
data/Gemfile
CHANGED
@@ -7,9 +7,9 @@ source :rubygems
|
|
7
7
|
# this is the last known commit that we tested against and is passing.
|
8
8
|
# keep closer track of this stuff to make bisecting easier and travis more
|
9
9
|
# accurate
|
10
|
-
|
11
|
-
# git 'git://github.com/slyphon/zookeeper.git', :
|
12
|
-
# gem 'zookeeper', '
|
10
|
+
|
11
|
+
# git 'git://github.com/slyphon/zookeeper.git', :tag => 'dev/zk/00000' do
|
12
|
+
# gem 'zookeeper', '~> 1.0.0'
|
13
13
|
# end
|
14
14
|
|
15
15
|
|
data/README.markdown
CHANGED
@@ -63,6 +63,14 @@ In addition to all of that, I would like to think that the public API the ZK::Cl
|
|
63
63
|
|
64
64
|
## NEWS ##
|
65
65
|
|
66
|
+
### v1.3.0 ###
|
67
|
+
|
68
|
+
Phusion Passenger and Unicorn users are encouraged to upgrade!
|
69
|
+
|
70
|
+
* __fork()__: ZK should now work reliably after a fork() if you call `reopen()` ASAP in the child process (before continuing any ZK work). Additionally, your event-handler (blocks set up with `zk.register`) will still work in the child. You will have to make calls like `zk.stat(path, :watch => true)` to tell ZooKeeper to notify you of events (as the child will have a new session), but everything should work.
|
71
|
+
|
72
|
+
* See the fork-handling documentation [on the wiki](http://github.com/slyphon/zk/wiki/Forking).
|
73
|
+
|
66
74
|
### v1.2.0 ###
|
67
75
|
|
68
76
|
You are __STRONGLY ENCOURAGED__ to go and look at the [CHANGELOG](http://git.io/tPbNBw) from the zookeeper 1.0.0 release
|
data/docs/examples/events_01.rb
CHANGED
data/docs/examples/events_02.rb
CHANGED
data/lib/zk/client/base.rb
CHANGED
@@ -85,7 +85,9 @@ module ZK
|
|
85
85
|
#
|
86
86
|
# @abstract Overridden in subclasses
|
87
87
|
def initialize(host, opts={})
|
88
|
-
#
|
88
|
+
# keep track of the process we were in when we started
|
89
|
+
@host = host
|
90
|
+
@pid = Process.pid
|
89
91
|
end
|
90
92
|
|
91
93
|
private
|
@@ -113,17 +115,40 @@ module ZK
|
|
113
115
|
#
|
114
116
|
# @return [Symbol] state of connection after operation
|
115
117
|
def reopen(timeout=nil)
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
118
|
+
# timeout ||= @session_timeout # XXX: @session_timeout ?
|
119
|
+
# cnx.reopen(timeout)
|
120
|
+
# @threadpool.start!
|
121
|
+
# state
|
120
122
|
end
|
121
123
|
|
122
124
|
# close the underlying connection and clear all pending events.
|
123
125
|
#
|
124
126
|
def close!
|
125
127
|
event_handler.clear!
|
126
|
-
wrap_state_closed_error { cnx.close
|
128
|
+
wrap_state_closed_error { cnx.close if cnx && !cnx.closed? }
|
129
|
+
end
|
130
|
+
|
131
|
+
# Connect to the server/cluster. This is called automatically by the
|
132
|
+
# constructor by default.
|
133
|
+
def connect(opts={})
|
134
|
+
end
|
135
|
+
|
136
|
+
# this method will wait until the underlying connection is connected.
|
137
|
+
# please note that when a connection is established, the underlying
|
138
|
+
# zookeeper gem performs this operation. you should only use this
|
139
|
+
# method if you have received a connecting event and want to wait
|
140
|
+
# until the connection has been re-established.
|
141
|
+
#
|
142
|
+
# this method will block until you reach the connected? state or timeout
|
143
|
+
# seconds have passed. if we enter another state, you will not be
|
144
|
+
# awakened in the current implementation, so this method is somewhat
|
145
|
+
# unsafe.
|
146
|
+
#
|
147
|
+
# use this with caution
|
148
|
+
#
|
149
|
+
# @private
|
150
|
+
def wait_until_connected(timeout=10)
|
151
|
+
cnx.wait_until_connected(timeout)
|
127
152
|
end
|
128
153
|
|
129
154
|
# Create a node with the given path. The node data will be the given data.
|
@@ -718,7 +743,11 @@ module ZK
|
|
718
743
|
num =
|
719
744
|
case level
|
720
745
|
when String, Symbol
|
721
|
-
|
746
|
+
begin
|
747
|
+
ZookeeperBase.const_get(:"ZOO_LOG_LEVEL_#{level.to_s.upcase}")
|
748
|
+
rescue NameError
|
749
|
+
nil
|
750
|
+
end
|
722
751
|
when Integer
|
723
752
|
level
|
724
753
|
end
|
@@ -865,6 +894,11 @@ module ZK
|
|
865
894
|
end
|
866
895
|
|
867
896
|
protected
|
897
|
+
# does the current pid match the one that created us?
|
898
|
+
def forked?
|
899
|
+
Process.pid != @pid
|
900
|
+
end
|
901
|
+
|
868
902
|
# @private
|
869
903
|
def check_rc(hash, inputs=nil)
|
870
904
|
code = hash[:rc]
|
data/lib/zk/client/threaded.rb
CHANGED
@@ -110,9 +110,13 @@ module ZK
|
|
110
110
|
# * see {https://github.com/slyphon/zk/wiki/EventDeliveryModel the wiki} for a
|
111
111
|
# discussion and demonstration of the effect of this setting.
|
112
112
|
#
|
113
|
-
# @option opts [Fixnum] :timeout
|
114
|
-
#
|
115
|
-
#
|
113
|
+
# @option opts [Fixnum] :timeout used as a default for calls to {#reopen}
|
114
|
+
# and {#connect} (including the initial default immediate connection)
|
115
|
+
#
|
116
|
+
# @option opts [true,false] :connect (true) Immediately connect to the
|
117
|
+
# server. It may be useful to pass false if you wish to do callback
|
118
|
+
# setup without passing a block. You must then call {#connect}
|
119
|
+
# explicitly.
|
116
120
|
#
|
117
121
|
# @yield [self] calls the block with the new instance after the event
|
118
122
|
# handler and threadpool have been set up, but before any connections
|
@@ -130,24 +134,57 @@ module ZK
|
|
130
134
|
tp_size = opts.fetch(:threadpool_size, DEFAULT_THREADPOOL_SIZE)
|
131
135
|
@threadpool = Threadpool.new(tp_size)
|
132
136
|
|
133
|
-
@
|
137
|
+
@connection_timeout = opts.fetch(:timeout, DEFAULT_TIMEOUT) # maybe move this into superclass?
|
134
138
|
@event_handler = EventHandler.new(self, opts)
|
135
139
|
|
136
140
|
@reconnect = opts.fetch(:reconnect, true)
|
137
141
|
|
138
|
-
@mutex =
|
142
|
+
@mutex = Monitor.new
|
139
143
|
|
140
144
|
@close_requested = false
|
141
145
|
|
142
146
|
yield self if block_given?
|
143
147
|
|
144
|
-
@
|
148
|
+
@mutex.synchronize do
|
149
|
+
connect if opts.fetch(:connect, true)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# @option opts [Fixnum] :timeout how long we will wait for the connection
|
154
|
+
# to be established. If timeout is nil, we will wait forever: *use
|
155
|
+
# carefully*.
|
156
|
+
def connect(opts={})
|
157
|
+
@mutex.synchronize do
|
158
|
+
return if @cnx
|
159
|
+
timeout = opts.fetch(:timeout, @connection_timeout)
|
160
|
+
@cnx = create_connection(@host, timeout, @event_handler.get_default_watcher_block)
|
161
|
+
end
|
145
162
|
end
|
146
163
|
|
147
164
|
# (see Base#reopen)
|
148
165
|
def reopen(timeout=nil)
|
166
|
+
# If we've forked, then we can call all sorts of normally dangerous
|
167
|
+
# stuff because we're the only thread.
|
168
|
+
if forked?
|
169
|
+
# ok, just to sanity check here
|
170
|
+
raise "[BUG] we hit the fork-reopening code in JRuby!!" if defined?(::JRUBY_VERSION)
|
171
|
+
|
172
|
+
logger.debug { "#{self.class}##{__method__} reopening everything, fork detected!" }
|
173
|
+
|
174
|
+
@mutex = Monitor.new
|
175
|
+
@threadpool.reopen_after_fork! # prune dead threadpool threads after a fork()
|
176
|
+
@event_handler.reopen_after_fork!
|
177
|
+
@pid = Process.pid
|
178
|
+
|
179
|
+
old_cnx, @cnx = @cnx, nil
|
180
|
+
old_cnx.close! if old_cnx # && !old_cnx.closed?
|
181
|
+
else
|
182
|
+
logger.debug { "#{self.class}##{__method__} not reopening, no fork detected" }
|
183
|
+
end
|
184
|
+
|
149
185
|
@mutex.synchronize { @close_requested = false }
|
150
|
-
|
186
|
+
connect
|
187
|
+
state
|
151
188
|
end
|
152
189
|
|
153
190
|
# (see Base#close!)
|
data/lib/zk/core_ext.rb
CHANGED
data/lib/zk/election.rb
CHANGED
@@ -239,7 +239,8 @@ module ZK
|
|
239
239
|
protected
|
240
240
|
# the inauguration, as it were
|
241
241
|
def acknowledge_win!
|
242
|
-
@zk.create(leader_ack_path, @data, :ephemeral => true)
|
242
|
+
@zk.create(leader_ack_path, @data, :ephemeral => true)
|
243
|
+
rescue Exceptions::NodeExists
|
243
244
|
end
|
244
245
|
|
245
246
|
# return the list of ephemeral vote nodes
|
data/lib/zk/event_handler.rb
CHANGED
@@ -32,19 +32,30 @@ module ZK
|
|
32
32
|
# :nodoc:
|
33
33
|
def initialize(zookeeper_client, opts={})
|
34
34
|
@zk = zookeeper_client
|
35
|
-
@callbacks = Hash.new { |h,k| h[k] = [] }
|
36
35
|
|
37
36
|
@thread_opt = opts.fetch(:thread, :single)
|
37
|
+
EventHandlerSubscription.class_for_thread_option(@thread_opt) # this is side-effecty, will raise an ArgumentError if given a bad value.
|
38
38
|
|
39
|
-
|
40
|
-
# value.
|
41
|
-
EventHandlerSubscription.class_for_thread_option(@thread_opt)
|
39
|
+
@mutex = nil
|
42
40
|
|
43
|
-
@
|
41
|
+
@callbacks = Hash.new { |h,k| h[k] = [] }
|
44
42
|
|
45
43
|
@outstanding_watches = VALID_WATCH_TYPES.inject({}) do |h,k|
|
46
44
|
h.tap { |x| x[k] = Set.new }
|
47
45
|
end
|
46
|
+
|
47
|
+
reopen_after_fork!
|
48
|
+
end
|
49
|
+
|
50
|
+
# do not call this method. it is inteded for use only when we've forked and
|
51
|
+
# all other threads are dead.
|
52
|
+
#
|
53
|
+
# @private
|
54
|
+
def reopen_after_fork!
|
55
|
+
logger.debug { "#{self.class}##{__method__} reopening callbacks" }
|
56
|
+
@mutex = Monitor.new
|
57
|
+
@callbacks.values.flatten.each { |cb| cb.reopen_after_fork! if cb.respond_to?(:reopen_after_fork!) }
|
58
|
+
nil
|
48
59
|
end
|
49
60
|
|
50
61
|
# @see ZK::Client::Base#register
|
@@ -292,7 +303,6 @@ module ZK
|
|
292
303
|
end
|
293
304
|
end
|
294
305
|
end
|
295
|
-
|
296
306
|
end # EventHandler
|
297
307
|
end # ZK
|
298
308
|
|
@@ -33,18 +33,6 @@ module ZK
|
|
33
33
|
@interests = prep_interests(opts[:only])
|
34
34
|
end
|
35
35
|
|
36
|
-
# unsubscribe from the path or state you were watching
|
37
|
-
# @see ZK::Client::Base#register
|
38
|
-
# def unsubscribe
|
39
|
-
# @event_handler.unregister(self)
|
40
|
-
# end
|
41
|
-
# alias :unregister :unsubscribe
|
42
|
-
|
43
|
-
# # @private
|
44
|
-
# def call(event)
|
45
|
-
# callback.call(event)
|
46
|
-
# end
|
47
|
-
|
48
36
|
# the Actor returns true for this
|
49
37
|
# @private
|
50
38
|
def async?
|
@@ -256,7 +256,12 @@ module ZK
|
|
256
256
|
def cleanup_lock_path!
|
257
257
|
logger.debug { "removing lock path #{@lock_path}" }
|
258
258
|
zk.delete(@lock_path)
|
259
|
-
|
259
|
+
|
260
|
+
begin
|
261
|
+
zk.delete(root_lock_path)
|
262
|
+
rescue NotEmpty
|
263
|
+
end
|
264
|
+
|
260
265
|
@lock_path = nil
|
261
266
|
end
|
262
267
|
end # LockerBase
|
data/lib/zk/message_queue.rb
CHANGED
@@ -120,9 +120,17 @@ module ZK
|
|
120
120
|
locks << lock
|
121
121
|
end
|
122
122
|
children.each do |path|
|
123
|
-
|
123
|
+
begin
|
124
|
+
@zk.delete("#{full_queue_path}/#{path}")
|
125
|
+
rescue ZK::Exceptions::NoNode
|
126
|
+
end
|
124
127
|
end
|
125
|
-
|
128
|
+
|
129
|
+
begin
|
130
|
+
@zk.delete(full_queue_path)
|
131
|
+
rescue ZK::Exceptions::NoNode
|
132
|
+
end
|
133
|
+
|
126
134
|
locks.each do |lock|
|
127
135
|
lock.unlock!
|
128
136
|
end
|
data/lib/zk/subscription.rb
CHANGED
@@ -20,7 +20,7 @@ module ZK
|
|
20
20
|
raise ArgumentError, "block must repsond_to?(:call)" unless block.respond_to?(:call)
|
21
21
|
@parent = parent
|
22
22
|
@callable = block
|
23
|
-
|
23
|
+
reopen_after_fork!
|
24
24
|
end
|
25
25
|
|
26
26
|
def unregister
|
@@ -33,6 +33,11 @@ module ZK
|
|
33
33
|
callable.call(*args)
|
34
34
|
end
|
35
35
|
|
36
|
+
# @private
|
37
|
+
def reopen_after_fork!
|
38
|
+
@mutex = Monitor.new
|
39
|
+
end
|
40
|
+
|
36
41
|
protected
|
37
42
|
def synchronize
|
38
43
|
@mutex.synchronize { yield }
|
@@ -45,6 +50,7 @@ module ZK
|
|
45
50
|
included do
|
46
51
|
alias_method_chain :unsubscribe, :threaded_callback
|
47
52
|
alias_method_chain :callable, :threaded_callback_wrapper
|
53
|
+
alias_method_chain :reopen_after_fork!, :threaded_refresh
|
48
54
|
end
|
49
55
|
|
50
56
|
def unsubscribe_with_threaded_callback
|
@@ -53,6 +59,11 @@ module ZK
|
|
53
59
|
unsubscribe_without_threaded_callback
|
54
60
|
end
|
55
61
|
end
|
62
|
+
|
63
|
+
def reopen_after_fork_with_threaded_refresh!
|
64
|
+
reopen_after_fork_without_threaded_refresh!
|
65
|
+
@threaded_callback = ThreadedCallback.new(@callable)
|
66
|
+
end
|
56
67
|
|
57
68
|
def callable_with_threaded_callback_wrapper(*args)
|
58
69
|
synchronize do
|
data/lib/zk/threaded_callback.rb
CHANGED
@@ -11,9 +11,11 @@ module ZK
|
|
11
11
|
def initialize(callback=nil, &blk)
|
12
12
|
@callback = callback || blk
|
13
13
|
@mutex = Monitor.new
|
14
|
-
|
15
|
-
@
|
16
|
-
|
14
|
+
|
15
|
+
@mutex.synchronize do
|
16
|
+
@running = true
|
17
|
+
reopen_after_fork!
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
21
|
def running?
|
@@ -36,9 +38,22 @@ module ZK
|
|
36
38
|
@queue.push(args)
|
37
39
|
end
|
38
40
|
|
41
|
+
# called after a fork to replace a dead delivery thread
|
42
|
+
# special case, there should be ONLY ONE THREAD RUNNING,
|
43
|
+
# (the one that survived the fork)
|
44
|
+
#
|
45
|
+
# @private
|
46
|
+
def reopen_after_fork!
|
47
|
+
return unless @running
|
48
|
+
return if @thread and @thread.alive?
|
49
|
+
@mutex = Monitor.new
|
50
|
+
@queue = Queue.new
|
51
|
+
@thread = spawn_dispatch_thread()
|
52
|
+
end
|
53
|
+
|
39
54
|
protected
|
40
|
-
def
|
41
|
-
|
55
|
+
def spawn_dispatch_thread
|
56
|
+
Thread.new do
|
42
57
|
while running?
|
43
58
|
args = @queue.pop
|
44
59
|
break if args == KILL_TOKEN
|
data/lib/zk/threadpool.rb
CHANGED
@@ -64,6 +64,17 @@ module ZK
|
|
64
64
|
true
|
65
65
|
end
|
66
66
|
|
67
|
+
# like the start! method, but checks for dead threads in the threadpool
|
68
|
+
# (which will happen after a fork())
|
69
|
+
# @private
|
70
|
+
def reopen_after_fork!
|
71
|
+
return false unless @running
|
72
|
+
@mutex = Monitor.new
|
73
|
+
@threadqueue = Queue.new
|
74
|
+
prune_dead_threads
|
75
|
+
spawn_threadpool
|
76
|
+
end
|
77
|
+
|
67
78
|
# register a block to be called back with unhandled exceptions that occur
|
68
79
|
# in the threadpool.
|
69
80
|
#
|
@@ -138,21 +149,41 @@ module ZK
|
|
138
149
|
logger.error { "#{msg}: #{e.to_std_format}" }
|
139
150
|
end
|
140
151
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
dispatch_to_error_handler(e)
|
152
|
+
def prune_dead_threads
|
153
|
+
@mutex.synchronize do
|
154
|
+
threads, @threadpool = @threadpool, []
|
155
|
+
return if threads.empty?
|
156
|
+
|
157
|
+
while th = threads.shift
|
158
|
+
begin
|
159
|
+
if th.join(0).nil?
|
160
|
+
@threadpool << th
|
151
161
|
end
|
162
|
+
rescue Exception => e
|
163
|
+
logger.error { "Caught exception pruning threads in the threadpool" }
|
164
|
+
logger.error { e.to_std_format }
|
152
165
|
end
|
153
166
|
end
|
167
|
+
end
|
168
|
+
end
|
154
169
|
|
155
|
-
|
170
|
+
def spawn_threadpool #:nodoc:
|
171
|
+
@mutex.synchronize do
|
172
|
+
until @threadpool.size >= @size.to_i
|
173
|
+
thread = Thread.new do
|
174
|
+
while @running
|
175
|
+
begin
|
176
|
+
op = @threadqueue.pop
|
177
|
+
break if op == KILL_TOKEN
|
178
|
+
op.call
|
179
|
+
rescue Exception => e
|
180
|
+
dispatch_to_error_handler(e)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
@threadpool << thread
|
186
|
+
end
|
156
187
|
end
|
157
188
|
end
|
158
189
|
end
|
data/lib/zk/version.rb
CHANGED
data/lib/zk.rb
CHANGED
@@ -13,6 +13,9 @@ require 'set'
|
|
13
13
|
require 'time'
|
14
14
|
require 'date'
|
15
15
|
|
16
|
+
module ZK
|
17
|
+
end
|
18
|
+
|
16
19
|
require 'zk/core_ext'
|
17
20
|
require 'zk/logging'
|
18
21
|
require 'zk/exceptions'
|
@@ -44,7 +47,7 @@ module ZK
|
|
44
47
|
end
|
45
48
|
|
46
49
|
unless @logger
|
47
|
-
@logger = Logger.new($stderr).tap { |n| n.level = Logger::ERROR }
|
50
|
+
@logger = Logger.new($stderr).tap { |n| n.level = ENV['ZK_DEBUG'] ? Logger::DEBUG : Logger::ERROR }
|
48
51
|
end
|
49
52
|
|
50
53
|
@default_host = 'localhost' unless @default_host
|
@@ -29,8 +29,18 @@ class EventCatcher
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def add(
|
32
|
+
def add(*args)
|
33
33
|
synchronize do
|
34
|
+
case args.length
|
35
|
+
when 2
|
36
|
+
sym, obj = args
|
37
|
+
when 1
|
38
|
+
obj = args.first
|
39
|
+
sym = obj.interest_key
|
40
|
+
else
|
41
|
+
raise ArgumentError, "Dunno how to handle args: #{args.inspect}"
|
42
|
+
end
|
43
|
+
|
34
44
|
logger.debug { "adding #{sym.inspect} #{obj.inspect}" }
|
35
45
|
events[sym] << obj
|
36
46
|
cond(sym).broadcast
|
@@ -39,6 +49,7 @@ class EventCatcher
|
|
39
49
|
cond(:all).broadcast
|
40
50
|
end
|
41
51
|
end
|
52
|
+
alias << add
|
42
53
|
|
43
54
|
def wait_for(ev_name, timeout=5)
|
44
55
|
cond(ev_name).wait(timeout)
|
data/spec/support/pendings.rb
CHANGED
@@ -35,6 +35,18 @@ module Pendings
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
def pending_rbx(msg)
|
39
|
+
if ZK.rubinius?
|
40
|
+
if block_given?
|
41
|
+
pending(msg) { yield }
|
42
|
+
else
|
43
|
+
pending(msg)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
yield if block_given?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
alias pending_rubinius pending_rbx
|
38
50
|
|
39
51
|
def pending_in_travis(msg)
|
40
52
|
# defined in the somewhat ill-named 00_test_port_attr.rb
|
data/spec/zk/client_spec.rb
CHANGED
@@ -31,5 +31,90 @@ describe ZK::Client::Threaded do
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
|
+
unless defined?(::JRUBY_VERSION)
|
36
|
+
describe :forked do
|
37
|
+
include_context 'connection opts'
|
38
|
+
|
39
|
+
before do
|
40
|
+
@base_path = '/zktests'
|
41
|
+
@pids_root = "#{@base_path}/pid"
|
42
|
+
|
43
|
+
ZK.open(*connection_args) do |z|
|
44
|
+
z.rm_rf(@base_path)
|
45
|
+
z.mkdir_p(@pids_root)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
after do
|
50
|
+
if @pid
|
51
|
+
begin
|
52
|
+
Process.kill('TERM', @pid)
|
53
|
+
pid, st = Process.wait2(@pid)
|
54
|
+
logger.debug { "child #{@pid} exited with status: #{st.inspect}" }
|
55
|
+
rescue Errno::ESRCH
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
@zk.close! if @zk
|
60
|
+
ZK.open(*connection_args) { |z| z.rm_rf(@base_path) }
|
61
|
+
end
|
62
|
+
|
63
|
+
it %[should deliver callbacks in the child] do
|
64
|
+
pending_in_travis "skip this test, flaky in travis"
|
65
|
+
pending_rbx('fails in rubinius') do
|
66
|
+
|
67
|
+
logger.debug { "Process.pid of parent: #{Process.pid}" }
|
68
|
+
|
69
|
+
@zk = ZK.new do |z|
|
70
|
+
z.on_connected do
|
71
|
+
logger.debug { "on_connected fired, writing pid to path #{@pids_root}/#{$$}" }
|
72
|
+
begin
|
73
|
+
z.create("#{@pids_root}/#{Process.pid}", Process.pid.to_s)
|
74
|
+
rescue ZK::Exceptions::NodeExists
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
@parent_pid = $$
|
80
|
+
|
81
|
+
@zk.create("#{@pids_root}/#{$$}", $$.to_s)
|
82
|
+
|
83
|
+
event_catcher = EventCatcher.new
|
84
|
+
|
85
|
+
@zk.register(@pids_root, :only => :child) do |event|
|
86
|
+
event_catcher << event
|
87
|
+
end
|
88
|
+
|
89
|
+
@pid = fork do
|
90
|
+
@zk.reopen
|
91
|
+
@zk.wait_until_connected
|
92
|
+
|
93
|
+
wait_until(3) { @zk.exists?("#{@pids_root}/#{$$}") }
|
94
|
+
|
95
|
+
logger.debug { "in child: child pid path exists?: %p" % [@zk.exists?("#{@pids_root}/#{$$}")] }
|
96
|
+
|
97
|
+
exit! 0
|
98
|
+
end
|
99
|
+
|
100
|
+
_, stat = Process.wait2(@pid)
|
101
|
+
|
102
|
+
stat.should_not be_signaled
|
103
|
+
stat.should be_exited
|
104
|
+
stat.should be_success
|
105
|
+
|
106
|
+
event_catcher.synchronize do
|
107
|
+
unless event_catcher.child.empty?
|
108
|
+
event_catcher.wait_for_child
|
109
|
+
event_catcher.child.should_not be_empty
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
@zk.should be_exists("#{@pids_root}/#{@pid}")
|
114
|
+
|
115
|
+
end
|
116
|
+
end # should deliver callbacks in the child
|
117
|
+
end # forked
|
118
|
+
end # # jruby guard
|
119
|
+
end # ZK::Client::Threaded
|
35
120
|
|
data/spec/zk/pool_spec.rb
CHANGED
@@ -28,7 +28,10 @@ describe ZK::Pool do
|
|
28
28
|
|
29
29
|
report_realtime("closing") do
|
30
30
|
ZK.open("localhost:#{ZK.test_port}") do |zk|
|
31
|
-
|
31
|
+
begin
|
32
|
+
zk.delete('/test_pool')
|
33
|
+
rescue ZK::Exceptions::NoNode
|
34
|
+
end
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
@@ -119,7 +122,10 @@ describe ZK::Pool do
|
|
119
122
|
@path = '/_testWatch'
|
120
123
|
|
121
124
|
@connection_pool.with_connection do |zk|
|
122
|
-
|
125
|
+
begin
|
126
|
+
zk.delete(@path)
|
127
|
+
rescue ZK::Exceptions::NoNode
|
128
|
+
end
|
123
129
|
end
|
124
130
|
|
125
131
|
@connection_pool.with_connection do |zk|
|
data/spec/zookeeper_spec.rb
CHANGED
data/zk.gemspec
CHANGED
@@ -12,8 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = %q{A high-level wrapper around the zookeeper driver}
|
13
13
|
s.description = s.summary + "\n"
|
14
14
|
|
15
|
-
|
16
|
-
s.add_runtime_dependency 'zookeeper', '~> 1.0.0.beta.1'
|
15
|
+
s.add_runtime_dependency 'zookeeper', '~> 1.0.2'
|
17
16
|
s.add_runtime_dependency 'backports', '~> 2.5.1'
|
18
17
|
|
19
18
|
s.files = `git ls-files`.split("\n")
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 1.
|
10
|
+
version: 1.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jonathan D. Simms
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2012-05-
|
19
|
+
date: 2012-05-09 00:00:00 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: zookeeper
|
@@ -26,14 +26,12 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 19
|
30
30
|
segments:
|
31
31
|
- 1
|
32
32
|
- 0
|
33
|
-
-
|
34
|
-
|
35
|
-
- 1
|
36
|
-
version: 1.0.0.beta.1
|
33
|
+
- 2
|
34
|
+
version: 1.0.2
|
37
35
|
type: :runtime
|
38
36
|
version_requirements: *id001
|
39
37
|
- !ruby/object:Gem::Dependency
|