zk 1.5.2 → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
data/Guardfile CHANGED
@@ -26,11 +26,20 @@ guard 'rspec', :version => 2 do
26
26
  when %r{^(?:zk/locker/locker_base|spec/shared/locker)}
27
27
  Dir["spec/zk/locker/*_spec.rb"]
28
28
 
29
+ when %r{^zk/client/(?:base|state_mixin)}
30
+ Dir['spec/zk/{client,client/*,zookeeper}_spec.rb']
31
+
29
32
  when 'zk' # .rb
30
33
  'spec' # run all tests
31
34
 
32
35
  else
33
- "spec/#{m[1]}_spec.rb"
36
+ generic = "spec/#{m[1]}_spec.rb"
37
+ if test(?f, generic)
38
+ generic
39
+ else
40
+ $stderr.puts "RUNNING ALL TESTS"
41
+ 'spec'
42
+ end
34
43
  end
35
44
  end
36
45
 
@@ -51,7 +51,7 @@ module ZK
51
51
  # the wrapped connection object
52
52
  # @private
53
53
  attr_reader :cnx
54
- protected :cnx
54
+ private :cnx
55
55
 
56
56
  # maps from a symbol given as an option, to the numeric error constant that should
57
57
  # not raise an exception
@@ -1020,7 +1020,7 @@ module ZK
1020
1020
  def raw_event_handler(event)
1021
1021
  end
1022
1022
 
1023
- protected
1023
+ private
1024
1024
  # does the current pid match the one that created us?
1025
1025
  def forked?
1026
1026
  Process.pid != @pid
@@ -1038,7 +1038,6 @@ module ZK
1038
1038
  check_rc(rv, opts)
1039
1039
  end
1040
1040
 
1041
- # @private
1042
1041
  # XXX: make this actually call the method on cnx
1043
1042
  def check_rc(rv_hash, inputs)
1044
1043
  code = rv_hash[:rc]
@@ -1078,7 +1077,6 @@ module ZK
1078
1077
  Set.new(ERROR_IGNORE_MAP.values_at(*sym_array))
1079
1078
  end
1080
1079
 
1081
- # @private
1082
1080
  def setup_watcher!(watch_type, opts, &b)
1083
1081
  event_handler.setup_watcher!(watch_type, opts, &b)
1084
1082
  end
@@ -78,7 +78,7 @@ module ZK
78
78
  watcher.register_state_handler(:expired_session, &block)
79
79
  end
80
80
 
81
- protected
81
+ private
82
82
  def wrap_state_closed_error
83
83
  yield
84
84
  rescue RuntimeError => e
@@ -45,10 +45,10 @@ module ZK
45
45
 
46
46
  # @private
47
47
  module Constants
48
- CLI_RUNNING = :running
49
- CLI_PAUSED = :paused
50
- CLI_CLOSE_REQ = :close_requested
51
- CLI_CLOSED = :closed
48
+ RUNNING = :running
49
+ PAUSED = :paused
50
+ CLOSE_REQ = :close_requested
51
+ CLOSED = :closed
52
52
  end
53
53
  include Constants
54
54
 
@@ -161,13 +161,12 @@ module ZK
161
161
 
162
162
  @reconnect = opts.fetch(:reconnect, true)
163
163
 
164
- @mutex = Monitor.new
165
- @cond = @mutex.new_cond
164
+ setup_locks
166
165
 
167
- @cli_state = CLI_RUNNING # this is to distinguish between *our* state and the underlying connection state
166
+ @client_state = RUNNING # this is to distinguish between *our* state and the underlying connection state
168
167
 
169
168
  # this is the last status update we've received from the underlying connection
170
- @last_cnx_state = Zookeeper::ZOO_CLOSED_STATE
169
+ @last_cnx_state = nil
171
170
 
172
171
  @retry_duration = opts.fetch(:retry_duration, nil).to_i
173
172
 
@@ -183,6 +182,15 @@ module ZK
183
182
 
184
183
  connect if opts.fetch(:connect, true)
185
184
  end
185
+
186
+ # ensure that the initializer and the reopen code set up the mutexes
187
+ # the same way (i.e. use a Monitor or a Mutex, no, really, I screwed
188
+ # this up once)
189
+ def setup_locks
190
+ @mutex = Monitor.new
191
+ @cond = @mutex.new_cond
192
+ end
193
+ private :setup_locks
186
194
 
187
195
  # @private
188
196
  def self.finalizer(hooks)
@@ -206,14 +214,18 @@ module ZK
206
214
 
207
215
  logger.debug { "reopening everything, fork detected!" }
208
216
 
209
- @mutex = Mutex.new
210
- @cond = ConditionVariable.new
217
+ setup_locks
218
+
211
219
  @pid = Process.pid
212
- @cli_state = CLI_RUNNING # reset state to running if we were paused
220
+ @client_state = RUNNING # reset state to running if we were paused
213
221
 
214
222
  old_cnx, @cnx = @cnx, nil
215
223
  old_cnx.close! if old_cnx # && !old_cnx.closed?
216
224
 
225
+ join_and_clear_reconnect_thread
226
+
227
+ @last_cnx_state = nil
228
+
217
229
  @mutex.synchronize do
218
230
  # it's important that we're holding the lock, as access to 'cnx' is
219
231
  # synchronized, and we want to avoid a race where event handlers
@@ -228,11 +240,12 @@ module ZK
228
240
  end
229
241
  else
230
242
  @mutex.synchronize do
231
- if @cli_state == CLI_PAUSED
243
+ if @client_state == PAUSED
232
244
  # XXX: what to do in this case? does it matter?
233
245
  end
234
246
 
235
247
  logger.debug { "reopening, no fork detected" }
248
+ @last_cnx_state = nil
236
249
  @cnx.reopen(timeout) # ok, we werent' forked, so just reopen
237
250
  end
238
251
  end
@@ -252,30 +265,37 @@ module ZK
252
265
  # @private
253
266
  def pause_before_fork_in_parent
254
267
  @mutex.synchronize do
255
- raise InvalidStateError, "client must be running? when you call #{__method__}" unless (@cli_state == CLI_RUNNING)
256
- @cli_state = CLI_PAUSED
268
+ raise InvalidStateError, "client must be running? when you call #{__method__}" unless (@client_state == RUNNING)
269
+ @client_state = PAUSED
257
270
 
258
271
  logger.debug { "#{self.class}##{__method__}" }
259
272
 
260
273
  @cond.broadcast
261
274
  end
262
275
 
276
+ join_and_clear_reconnect_thread
277
+
263
278
  # the compact is here because the @cnx *may* be nil when this callback is fired by the
264
279
  # ForkHook (in the case of ZK.open). The race is between the GC calling the finalizer
265
280
  [@event_handler, @threadpool, @cnx].compact.each(&:pause_before_fork_in_parent)
266
281
  ensure
267
- logger.debug { "#{self.class}##{__method__} returning" }
282
+ logger.debug { "##{__method__} returning" }
268
283
  end
269
284
 
270
285
  # @private
271
286
  def resume_after_fork_in_parent
272
287
  @mutex.synchronize do
273
- raise InvalidStateError, "client must be paused? when you call #{__method__}" unless (@cli_state == CLI_PAUSED)
274
- @cli_state = CLI_RUNNING
288
+ raise InvalidStateError, "client must be paused? when you call #{__method__}" unless (@client_state == PAUSED)
289
+ @client_state = RUNNING
275
290
 
276
- logger.debug { "#{self.class}##{__method__}" }
291
+ logger.debug { "##{__method__}" }
277
292
 
278
- [@cnx, @event_handler, @threadpool].compact.each(&:resume_after_fork_in_parent)
293
+ if @cnx
294
+ @cnx.resume_after_fork_in_parent
295
+ spawn_reconnect_thread
296
+ end
297
+
298
+ [@event_handler, @threadpool].compact.each(&:resume_after_fork_in_parent)
279
299
 
280
300
  @cond.broadcast
281
301
  end
@@ -291,12 +311,14 @@ module ZK
291
311
  #
292
312
  def close!
293
313
  @mutex.synchronize do
294
- return if [:closed, :close_requested].include?(@cli_state)
314
+ return if [:closed, :close_requested].include?(@client_state)
295
315
  logger.debug { "moving to :close_requested state" }
296
- @cli_state = CLI_CLOSE_REQ
316
+ @client_state = CLOSE_REQ
297
317
  @cond.broadcast
298
318
  end
299
319
 
320
+ join_and_clear_reconnect_thread
321
+
300
322
  on_tpool = on_threadpool?
301
323
 
302
324
  # Ok, so the threadpool will wait up to N seconds while joining each thread.
@@ -308,6 +330,7 @@ module ZK
308
330
  # and wait for it to exit
309
331
  #
310
332
  shutdown_thread = Thread.new do
333
+ Thread.current[:name] = 'shutdown'
311
334
  @threadpool.shutdown(10)
312
335
 
313
336
  # this will call #close
@@ -315,7 +338,8 @@ module ZK
315
338
 
316
339
  @mutex.synchronize do
317
340
  logger.debug { "moving to :closed state" }
318
- @cli_state = CLI_CLOSED
341
+ @client_state = CLOSED
342
+ @last_cnx_state = nil
319
343
  @cond.broadcast
320
344
  end
321
345
  end
@@ -348,15 +372,6 @@ module ZK
348
372
  @mutex.synchronize do
349
373
  @last_cnx_state = event.state
350
374
 
351
- if event.client_invalid? and @reconnect and not dead_or_dying?
352
- logger.error { "Got event #{event.state_name}, calling reopen(0)! things may be messed up until this works itself out!" }
353
-
354
- # reopen(0) means that we don't want to wait for the connection
355
- # to reach the connected state before returning as we're on the
356
- # event thread.
357
- reopen(0)
358
- end
359
-
360
375
  @cond.broadcast # wake anyone waiting for a connection state update
361
376
  end
362
377
  rescue Exception => e
@@ -364,26 +379,47 @@ module ZK
364
379
  end
365
380
 
366
381
  def closed?
367
- return true if @mutex.synchronize { @cli_state == CLI_CLOSED }
382
+ return true if @mutex.synchronize { @client_state == CLOSED }
368
383
  super
369
384
  end
370
385
 
371
386
  # are we in running (not-paused) state?
387
+ # @private
372
388
  def running?
373
- @mutex.synchronize { @cli_state == CLI_RUNNING }
389
+ @mutex.synchronize { @client_state == RUNNING }
374
390
  end
375
391
 
376
392
  # are we in paused state?
393
+ # @private
377
394
  def paused?
378
- @mutex.synchronize { @cli_state == CLI_PAUSED }
395
+ @mutex.synchronize { @client_state == PAUSED }
379
396
  end
380
397
 
381
398
  # has shutdown time arrived?
399
+ # @private
382
400
  def close_requested?
383
- @mutex.synchronize { @cli_state == CLI_CLOSE_REQ }
401
+ @mutex.synchronize { @client_state == CLOSE_REQ }
384
402
  end
385
403
 
386
- protected
404
+ # @private
405
+ def wait_until_connected_or_dying(timeout)
406
+ time_to_stop = Time.now + timeout
407
+
408
+ @mutex.synchronize do
409
+ while (@last_cnx_state != Zookeeper::ZOO_CONNECTED_STATE) && (Time.now < time_to_stop) && (@client_state == RUNNING)
410
+ @cond.wait(timeout)
411
+ end
412
+
413
+ logger.debug { "@last_cnx_state: #{@last_cnx_state.inspect}, time_left? #{Time.now.to_f < time_to_stop.to_f}, @client_state: #{@client_state.inspect}" }
414
+ end
415
+ end
416
+
417
+ private
418
+ # this is just here so we can see it in stack traces
419
+ def reopen_after_session_expired
420
+ reopen
421
+ end
422
+
387
423
  # in the threaded version of the client, synchronize access around cnx
388
424
  # so that callers don't wind up with a nil object when we're in the middle
389
425
  # of reopening it
@@ -391,6 +427,58 @@ module ZK
391
427
  @mutex.synchronize { @cnx }
392
428
  end
393
429
 
430
+ def reconnect_thread_body
431
+ Thread.current[:name] = 'reconnect'
432
+ while @reconnect # too clever?
433
+ @mutex.synchronize do
434
+ # either we havne't seen a valid session update from this
435
+ # connection yet, or we're doing fine, so just wait
436
+ @cond.wait_while { !seen_session_state_event? or (valid_session_state? and (@client_state == RUNNING)) }
437
+
438
+ # we've entered into a non-running state, so we exit
439
+ # note: need to restart this thread after a fork in parent
440
+ if @client_state != RUNNING
441
+ logger.debug { "session failure watcher thread exiting, @client_state: #{@client_state}" }
442
+ return
443
+ end
444
+
445
+ # if we know that this session was valid once and it has now
446
+ # become invalid we call reopen
447
+ #
448
+ if seen_session_state_event? and not valid_session_state?
449
+ logger.debug { "session state was invalid, calling reopen" }
450
+
451
+ # reopen will reset @last_cnx_state so that
452
+ # seen_session_state_event? will return false until the first
453
+ # event has been delivered on the new connection
454
+ rv = reopen_after_session_expired
455
+
456
+ logger.debug { "reopen returned: #{rv.inspect}" }
457
+ end
458
+ end
459
+ end
460
+ ensure
461
+ logger.debug { "reconnect thread exiting" }
462
+ end
463
+
464
+ def join_and_clear_reconnect_thread
465
+ return unless @reconnect_thread
466
+ begin
467
+ # this should never time out but, just to make sure we don't hang forever
468
+ unless @reconnect_thread.join(30)
469
+ logger.error { "timed out waiting for reconnect thread to join! something is hosed!" }
470
+ end
471
+ rescue Exception => e
472
+ logger.error { "caught exception joining reconnect thread" }
473
+ logger.error { e.to_std_format }
474
+ end
475
+ @reconnect_thread = nil
476
+ end
477
+
478
+ def spawn_reconnect_thread
479
+ @reconnect_thread ||= Thread.new(&method(:reconnect_thread_body))
480
+ end
481
+
394
482
  def call_and_check_rc(meth, opts)
395
483
  if retry_duration = (opts.delete(:retry_duration) || @retry_duration)
396
484
  begin
@@ -400,7 +488,7 @@ module ZK
400
488
 
401
489
  wait_until_connected_or_dying(retry_duration)
402
490
 
403
- if (@last_cnx_state != Zookeeper::ZOO_CONNECTED_STATE) || (Time.now > time_to_stop) || (@cli_state != CLI_RUNNING)
491
+ if (@last_cnx_state != Zookeeper::ZOO_CONNECTED_STATE) || (Time.now > time_to_stop) || (@client_state != RUNNING)
404
492
  raise e
405
493
  else
406
494
  retry
@@ -411,16 +499,20 @@ module ZK
411
499
  end
412
500
  end
413
501
 
414
- def wait_until_connected_or_dying(timeout)
415
- time_to_stop = Time.now + timeout
416
-
417
- @mutex.synchronize do
418
- while (@last_cnx_state != Zookeeper::ZOO_CONNECTED_STATE) && (Time.now < time_to_stop) && (@cli_state == CLI_RUNNING)
419
- @cond.wait(timeout)
420
- end
502
+ # have we gotten a status event for the current connection?
503
+ # this method is not synchronized
504
+ def seen_session_state_event?
505
+ !!@last_cnx_state
506
+ end
421
507
 
422
- logger.debug { "@last_cnx_state: #{@last_cnx_state}, time_left? #{Time.now.to_f < time_to_stop.to_f}, @cli_state: #{@cli_state.inspect}" }
423
- end
508
+ # we've seen a session state from the cnx, and it was not "omg we're screwed"
509
+ # will return false if we havne't gotten a session event yet
510
+ #
511
+ # this method is not synchronized
512
+ def valid_session_state?
513
+ # this is kind of icky, but the SESSION_INVALID and AUTH_FAILED states
514
+ # are both negative numbers
515
+ @last_cnx_state and (@last_cnx_state >= 0)
424
516
  end
425
517
 
426
518
  def create_connection(*args)
@@ -428,14 +520,14 @@ module ZK
428
520
  end
429
521
 
430
522
  def dead_or_dying?
431
- (@cli_state == CLI_CLOSE_REQ) || (@cli_state == CLI_CLOSED)
523
+ (@client_state == CLOSE_REQ) || (@client_state == CLOSED)
432
524
  end
433
525
 
434
- private
435
526
  def unlocked_connect(opts={})
436
527
  return if @cnx
437
528
  timeout = opts.fetch(:timeout, @connection_timeout)
438
529
  @cnx = create_connection(@host, timeout, @event_handler.get_default_watcher_block)
530
+ spawn_reconnect_thread
439
531
  end
440
532
  end
441
533
  end
data/lib/zk/election.rb CHANGED
@@ -150,7 +150,7 @@ module ZK
150
150
  end
151
151
  end
152
152
 
153
- protected
153
+ private
154
154
  def create_root_path!
155
155
  @zk.mkdir_p(root_vote_path)
156
156
  end
@@ -244,7 +244,7 @@ module ZK
244
244
  end
245
245
  end
246
246
 
247
- protected
247
+ private
248
248
  # the inauguration, as it were
249
249
  def acknowledge_win!
250
250
  @zk.create(leader_ack_path, @data, :ephemeral => true)
@@ -411,7 +411,7 @@ module ZK
411
411
  end
412
412
  end
413
413
 
414
- protected
414
+ private
415
415
  def the_king_is_dead
416
416
  synchronize do
417
417
  safe_call(*@leader_death_cbs)
@@ -196,7 +196,6 @@ module ZK
196
196
  end
197
197
 
198
198
  public
199
-
200
199
  # used during shutdown to clear registered listeners
201
200
  # @private
202
201
  def clear! #:nodoc:
@@ -303,13 +302,11 @@ module ZK
303
302
  end
304
303
  end
305
304
 
306
- protected
307
- # @private
305
+ private
308
306
  def watcher_callback
309
307
  Zookeeper::Callbacks::WatcherCallback.create { |event| process(event) }
310
308
  end
311
309
 
312
- # @private
313
310
  def state_key(arg)
314
311
  int =
315
312
  case arg
@@ -326,7 +323,6 @@ module ZK
326
323
  raise ArgumentError, "#{arg} is not a valid zookeeper state", caller
327
324
  end
328
325
 
329
- # @private
330
326
  def safe_call(callbacks, *args)
331
327
  callbacks.each do |cb|
332
328
  next unless cb.respond_to?(:call)
@@ -52,7 +52,7 @@ module ZK
52
52
  def resume_after_fork_in_parent
53
53
  end
54
54
 
55
- protected
55
+ private
56
56
  def prep_interests(a)
57
57
  # logger.debug { "prep_interests: #{a.inspect}" }
58
58
  return ALL_EVENT_SET if a.nil?
@@ -53,7 +53,7 @@ module ZK
53
53
  true
54
54
  end
55
55
 
56
- protected
56
+ private
57
57
  # the node that is next-lowest in sequence number to ours, the one we
58
58
  # watch for updates to
59
59
  def next_lowest_node
@@ -230,7 +230,7 @@ module ZK
230
230
  end
231
231
  end
232
232
 
233
- protected
233
+ private
234
234
  def synchronize
235
235
  @mutex.synchronize { yield }
236
236
  end
@@ -92,7 +92,7 @@ module ZK
92
92
  end
93
93
  alias got_lock? got_read_lock?
94
94
 
95
- protected
95
+ private
96
96
  # TODO: make this generic, can either block or non-block
97
97
  def block_until_read_lock!
98
98
  begin
data/lib/zk/mongoid.rb CHANGED
@@ -118,6 +118,7 @@ module ZK
118
118
  Thread.current.zk_mongoid_lock_registry ||= { :shared => Set.new, :exclusive => Set.new }
119
119
  end
120
120
 
121
+ private
121
122
  def zk_add_path_lock(opts={})
122
123
  mode, name = opts.values_at(:mode, :name)
123
124
 
data/lib/zk/pool.rb CHANGED
@@ -140,7 +140,7 @@ module ZK
140
140
  @state
141
141
  end
142
142
 
143
- protected
143
+ private
144
144
  def synchronize
145
145
  @mutex.synchronize { yield }
146
146
  end
@@ -255,7 +255,7 @@ module ZK
255
255
  @mutex.synchronize { @connections.size < @max_clients }
256
256
  end
257
257
 
258
- protected
258
+ private
259
259
  def populate_pool!(num_cnx)
260
260
  num_cnx.times { add_connection! }
261
261
  end
@@ -54,7 +54,7 @@ module ZK
54
54
  @mutex = Monitor.new
55
55
  end
56
56
 
57
- protected
57
+ private
58
58
  def synchronize
59
59
  @mutex.synchronize { yield }
60
60
  end
@@ -116,7 +116,7 @@ module ZK
116
116
  end
117
117
  end
118
118
 
119
- protected
119
+ private
120
120
  # intentionally *not* synchronized
121
121
  def spawn_dispatch_thread
122
122
  @thread = Thread.new(&method(:dispatch_thread_body))
@@ -133,7 +133,7 @@ module ZK
133
133
  @cond.wait(@mutex) while @array.empty? and @state == :running
134
134
 
135
135
  if @state != :running
136
- logger.warn { "ThreadedCallback, state is #{@state.inspect}, returning" }
136
+ logger.debug { "ThreadedCallback, state is #{@state.inspect}, returning" }
137
137
  return
138
138
  end
139
139
 
data/lib/zk/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ZK
2
- VERSION = "1.5.2"
2
+ VERSION = "1.5.3"
3
3
  end
@@ -24,16 +24,11 @@ shared_context 'threaded client connection' do
24
24
  # raise @threadpool_exception if @threadpool_exception
25
25
  # logger.debug { "threaded client connection - after hook" }
26
26
 
27
- if @zk.closed?
28
- logger.debug { "zk was closed, calling reopen" }
29
- @zk.reopen
30
- end
27
+ @zk.close! if @zk and not @zk.closed?
31
28
 
32
- wait_until(5) { @zk.connected? }
33
-
34
- @zk.rm_rf(@base_path)
35
- @zk.close!
36
- wait_until(5) { @zk.closed? }
29
+ ZK.open(*connection_args) do |z|
30
+ z.rm_rf(@base_path)
31
+ end
37
32
 
38
33
  # logger.debug { "threaded client connection - end after hook" }
39
34
  end
@@ -298,15 +298,20 @@ shared_examples_for 'client' do
298
298
 
299
299
  describe 'reconnection' do
300
300
  it %[should if it receives a client_invalid? event] do
301
- flexmock(@zk) do |m|
302
- m.should_receive(:reopen).with(0).once
303
- end
301
+ logger.debug { "about to cause the reconnection" }
304
302
 
305
303
  props = { :session_event? => true, :client_invalid? => true, :state_name => 'ZOO_EXPIRED_SESSION_STATE', :state => Zookeeper::ZOO_EXPIRED_SESSION_STATE }
306
304
 
307
305
  bogus_event = flexmock(:expired_session_event, props)
308
306
 
309
- @zk.raw_event_handler(bogus_event)
307
+ th = Thread.new do
308
+ @zk.raw_event_handler(bogus_event)
309
+ end
310
+
311
+ @zk.wait_until_connected_or_dying(5)
312
+ @zk.should be_connected
313
+
314
+ th.join(2).should == th
310
315
  end
311
316
  end # reconnection
312
317
 
data/spec/spec_helper.rb CHANGED
@@ -110,8 +110,10 @@ class ::Thread
110
110
  end
111
111
 
112
112
  if RUBY_VERSION == '1.9.3'
113
+ Thread.current[:name] = 'main'
114
+
113
115
  trap('USR1') do
114
- threads = Thread.list.map { |th| { :inspect => th.inspect, :calback => th[:callback], :backtrace => th.backtrace } }
116
+ threads = Thread.list.map { |th| { :inspect => th.inspect, :name => th[:name], :calback => th[:callback], :backtrace => th.backtrace } }
115
117
  pp threads
116
118
  end
117
119
  end
@@ -3,14 +3,13 @@ module ZK
3
3
 
4
4
  def self.logging_gem_setup
5
5
  layout = ::Logging.layouts.pattern(
6
- :pattern => '%.1l, [%d #%p] %30.30c{2}: %m\n',
7
- :date_pattern => '%Y-%m-%d %H:%M:%S.%6N'
6
+ :pattern => '%.1l, [%d #%p] (%9.9T) %25.25c{2}: %m\n',
7
+ :date_pattern => '%H:%M:%S.%6N'
8
8
  )
9
9
 
10
-
11
10
  appender = ENV['ZK_DEBUG'] ? ::Logging.appenders.stderr : ::Logging.appenders.file(ZK::TEST_LOG_PATH)
12
11
  appender.layout = layout
13
- appender.immediate_at = "debug,info,warn,error,fatal"
12
+ # appender.immediate_at = "debug,info,warn,error,fatal"
14
13
  # appender.auto_flushing = true
15
14
  appender.auto_flushing = 25
16
15
  appender.flush_period = 5
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: 7
4
+ hash: 5
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 5
9
- - 2
10
- version: 1.5.2
9
+ - 3
10
+ version: 1.5.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jonathan D. Simms