zk 0.9.1 → 1.0.0.rc.1
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/.gitignore +2 -2
- data/Gemfile +3 -4
- data/README.markdown +14 -5
- data/RELEASES.markdown +69 -1
- data/Rakefile +50 -18
- data/docs/examples/block_until_node_deleted_ex.rb +63 -0
- data/docs/examples/events_01.rb +36 -0
- data/docs/examples/events_02.rb +41 -0
- data/lib/{z_k → zk}/client/base.rb +87 -30
- data/lib/{z_k → zk}/client/conveniences.rb +0 -1
- data/lib/{z_k → zk}/client/state_mixin.rb +0 -0
- data/lib/zk/client/threaded.rb +196 -0
- data/lib/{z_k → zk}/client/unixisms.rb +0 -0
- data/lib/zk/client.rb +59 -0
- data/lib/zk/core_ext.rb +75 -0
- data/lib/{z_k → zk}/election.rb +0 -0
- data/lib/zk/event.rb +168 -0
- data/lib/{z_k → zk}/event_handler.rb +53 -28
- data/lib/zk/event_handler_subscription.rb +68 -0
- data/lib/{z_k → zk}/exceptions.rb +38 -23
- data/lib/zk/extensions.rb +79 -0
- data/lib/{z_k → zk}/find.rb +0 -0
- data/lib/{z_k → zk}/locker.rb +0 -0
- data/lib/{z_k → zk}/logging.rb +0 -0
- data/lib/{z_k → zk}/message_queue.rb +8 -4
- data/lib/{z_k → zk}/mongoid.rb +0 -0
- data/lib/{z_k → zk}/pool.rb +0 -0
- data/lib/zk/stat.rb +115 -0
- data/lib/{z_k → zk}/threadpool.rb +52 -4
- data/lib/zk/version.rb +3 -0
- data/lib/zk.rb +238 -1
- data/spec/message_queue_spec.rb +2 -2
- data/spec/shared/client_contexts.rb +8 -20
- data/spec/shared/client_examples.rb +136 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/support/event_catcher.rb +11 -0
- data/spec/support/exist_matcher.rb +6 -0
- data/spec/support/logging.rb +2 -1
- data/spec/watch_spec.rb +194 -10
- data/spec/{z_k → zk}/client/locking_and_session_death_spec.rb +0 -32
- data/spec/zk/client_spec.rb +23 -0
- data/spec/{z_k → zk}/election_spec.rb +0 -0
- data/spec/{z_k → zk}/extensions_spec.rb +0 -0
- data/spec/{z_k → zk}/locker_spec.rb +0 -40
- data/spec/zk/module_spec.rb +185 -0
- data/spec/{z_k → zk}/mongoid_spec.rb +0 -2
- data/spec/{z_k → zk}/pool_spec.rb +0 -2
- data/spec/{z_k → zk}/threadpool_spec.rb +32 -4
- data/spec/zookeeper_spec.rb +1 -6
- data/zk.gemspec +2 -2
- metadata +64 -56
- data/lib/z_k/client/continuation_proxy.rb +0 -109
- data/lib/z_k/client/drop_box.rb +0 -98
- data/lib/z_k/client/multiplexed.rb +0 -28
- data/lib/z_k/client/threaded.rb +0 -76
- data/lib/z_k/client.rb +0 -35
- data/lib/z_k/event_handler_subscription.rb +0 -36
- data/lib/z_k/extensions.rb +0 -155
- data/lib/z_k/version.rb +0 -3
- data/lib/z_k.rb +0 -97
- data/spec/z_k/client/drop_box_spec.rb +0 -90
- data/spec/z_k/client/multiplexed_spec.rb +0 -20
- data/spec/z_k/client_spec.rb +0 -7
@@ -0,0 +1,68 @@
|
|
1
|
+
module ZK
|
2
|
+
# the subscription object that is passed back from subscribing
|
3
|
+
# to events.
|
4
|
+
# @see ZK::Client::Base#register
|
5
|
+
class EventHandlerSubscription
|
6
|
+
# the event handler associated with this subscription
|
7
|
+
# @return [EventHandler]
|
8
|
+
attr_accessor :event_handler
|
9
|
+
|
10
|
+
# the path this subscription is for
|
11
|
+
# @return [String]
|
12
|
+
attr_accessor :path
|
13
|
+
|
14
|
+
# the block associated with the path
|
15
|
+
# @return [Proc]
|
16
|
+
attr_accessor :callback
|
17
|
+
|
18
|
+
# an array of what kinds of events this handler is interested in receiving
|
19
|
+
#
|
20
|
+
# @return [Set] containing any combination of :create, :change, :delete,
|
21
|
+
# or :children
|
22
|
+
#
|
23
|
+
# @private
|
24
|
+
attr_accessor :interests
|
25
|
+
|
26
|
+
ALL_EVENTS = [:created, :deleted, :changed, :child].freeze unless defined?(ALL_EVENTS)
|
27
|
+
ALL_EVENT_SET = Set.new(ALL_EVENTS).freeze unless defined?(ALL_EVENT_SET)
|
28
|
+
|
29
|
+
# @private
|
30
|
+
def initialize(event_handler, path, callback, interests)
|
31
|
+
@event_handler, @path, @callback = event_handler, path, callback
|
32
|
+
@interests = prep_interests(interests)
|
33
|
+
end
|
34
|
+
|
35
|
+
# unsubscribe from the path or state you were watching
|
36
|
+
# @see ZK::Client::Base#register
|
37
|
+
def unsubscribe
|
38
|
+
@event_handler.unregister(self)
|
39
|
+
end
|
40
|
+
alias :unregister :unsubscribe
|
41
|
+
|
42
|
+
# @private
|
43
|
+
def call(event)
|
44
|
+
callback.call(event)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def prep_interests(a)
|
49
|
+
return ALL_EVENT_SET if a.nil?
|
50
|
+
|
51
|
+
rval =
|
52
|
+
case a
|
53
|
+
when Array
|
54
|
+
Set.new(a)
|
55
|
+
when Symbol
|
56
|
+
Set.new([a])
|
57
|
+
else
|
58
|
+
raise ArgumentError, "Don't know how to handle interests: #{a.inspect}"
|
59
|
+
end
|
60
|
+
|
61
|
+
rval.tap do |rv|
|
62
|
+
invalid = (rv - ALL_EVENT_SET)
|
63
|
+
raise ArgumentError, "Invalid event name(s) #{invalid.to_a.inspect} given" unless invalid.empty?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
@@ -1,27 +1,29 @@
|
|
1
1
|
module ZK
|
2
2
|
module Exceptions
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
3
|
+
silence_warnings do
|
4
|
+
OK = 0
|
5
|
+
# System and server-side errors
|
6
|
+
SYSTEMERROR = -1
|
7
|
+
RUNTIMEINCONSISTENCY = SYSTEMERROR - 1
|
8
|
+
DATAINCONSISTENCY = SYSTEMERROR - 2
|
9
|
+
CONNECTIONLOSS = SYSTEMERROR - 3
|
10
|
+
MARSHALLINGERROR = SYSTEMERROR - 4
|
11
|
+
UNIMPLEMENTED = SYSTEMERROR - 5
|
12
|
+
OPERATIONTIMEOUT = SYSTEMERROR - 6
|
13
|
+
BADARGUMENTS = SYSTEMERROR - 7
|
14
|
+
# API errors
|
15
|
+
APIERROR = -100;
|
16
|
+
NONODE = APIERROR - 1 # Node does not exist
|
17
|
+
NOAUTH = APIERROR - 2 # Current operation not permitted
|
18
|
+
BADVERSION = APIERROR - 3 # Version conflict
|
19
|
+
NOCHILDRENFOREPHEMERALS = APIERROR - 8
|
20
|
+
NODEEXISTS = APIERROR - 10
|
21
|
+
NOTEMPTY = APIERROR - 11
|
22
|
+
SESSIONEXPIRED = APIERROR - 12
|
23
|
+
INVALIDCALLBACK = APIERROR - 13
|
24
|
+
INVALIDACL = APIERROR - 14
|
25
|
+
AUTHFAILED = APIERROR - 15 # client authentication failed
|
26
|
+
end
|
25
27
|
|
26
28
|
|
27
29
|
# these errors are returned rather than the driver level errors
|
@@ -92,7 +94,7 @@ module ZK
|
|
92
94
|
INVALIDCALLBACK => InvalidCallback,
|
93
95
|
INVALIDACL => InvalidACL,
|
94
96
|
AUTHFAILED => AuthFailed,
|
95
|
-
}
|
97
|
+
}.freeze unless defined?(ERROR_MAP)
|
96
98
|
|
97
99
|
# base class of ZK generated errors (not driver-level errors)
|
98
100
|
class ZKError < StandardError; end
|
@@ -120,6 +122,19 @@ module ZK
|
|
120
122
|
|
121
123
|
# raised when someone performs a blocking ZK operation on the event dispatch thread.
|
122
124
|
class EventDispatchThreadException < ZKError; end
|
125
|
+
|
126
|
+
# raised when a chrooted conection is requested but the root doesn't exist
|
127
|
+
class ChrootPathDoesNotExistError < NoNode
|
128
|
+
def initialize(host_string, chroot_path)
|
129
|
+
super("Chrooted connection to #{host_string} at #{chroot_path} requested, but path did not exist")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class ChrootMustStartWithASlashError < ArgumentError
|
134
|
+
def initialize(erroneous_string)
|
135
|
+
super("Chroot strings must start with a '/' you provided: #{erroneous_string.inspect}")
|
136
|
+
end
|
137
|
+
end
|
123
138
|
end
|
124
139
|
end
|
125
140
|
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module ZK
|
2
|
+
# this is taken from activesupport-3.2.3, and pasted here so that we don't conflict if someone
|
3
|
+
# is using us as part of a rails app
|
4
|
+
#
|
5
|
+
# i've removed the code that includes InstanceMethods (tftfy)
|
6
|
+
# @private
|
7
|
+
module Concern
|
8
|
+
def self.extended(base)
|
9
|
+
base.instance_variable_set("@_dependencies", [])
|
10
|
+
end
|
11
|
+
|
12
|
+
def append_features(base)
|
13
|
+
if base.instance_variable_defined?("@_dependencies")
|
14
|
+
base.instance_variable_get("@_dependencies") << self
|
15
|
+
return false
|
16
|
+
else
|
17
|
+
return false if base < self
|
18
|
+
@_dependencies.each { |dep| base.send(:include, dep) }
|
19
|
+
super
|
20
|
+
base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
|
21
|
+
base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def included(base = nil, &block)
|
26
|
+
if base.nil?
|
27
|
+
@_included_block = block
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module Extensions
|
35
|
+
# some extensions to the ZookeeperCallbacks classes, mainly convenience
|
36
|
+
# interrogators
|
37
|
+
module Callbacks
|
38
|
+
module Callback
|
39
|
+
extend Concern
|
40
|
+
|
41
|
+
# allow access to the connection that fired this callback
|
42
|
+
attr_accessor :zk
|
43
|
+
|
44
|
+
module ClassMethods
|
45
|
+
# allows for easier construction of a user callback block that will be
|
46
|
+
# called with the callback object itself as an argument.
|
47
|
+
#
|
48
|
+
# *args, if given, will be passed on *after* the callback
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
#
|
52
|
+
# WatcherCallback.create do |cb|
|
53
|
+
# puts "watcher callback called with argument: #{cb.inspect}"
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# "watcher callback called with argument: #<ZookeeperCallbacks::WatcherCallback:0x1018a3958 @state=3, @type=1, ...>"
|
57
|
+
#
|
58
|
+
#
|
59
|
+
def create(*args, &block)
|
60
|
+
cb_inst = new { block.call(cb_inst) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end # Callback
|
64
|
+
end # Callbacks
|
65
|
+
end # Extensions
|
66
|
+
end # ZK
|
67
|
+
|
68
|
+
# ZookeeperCallbacks::Callback.extend(ZK::Extensions::Callbacks::Callback)
|
69
|
+
ZookeeperCallbacks::Callback.send(:include, ZK::Extensions::Callbacks::Callback)
|
70
|
+
|
71
|
+
# Include the InterruptedSession module in key ZookeeperExceptions to allow
|
72
|
+
# clients to catch a single error type when waiting on a node (for example)
|
73
|
+
|
74
|
+
[:ConnectionClosed, :NotConnected, :SessionExpired, :SessionMoved, :ConnectionLoss].each do |class_name|
|
75
|
+
ZookeeperExceptions::ZookeeperException.const_get(class_name).tap do |klass|
|
76
|
+
klass.__send__(:include, ZK::Exceptions::InterruptedSession)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
data/lib/{z_k → zk}/find.rb
RENAMED
File without changes
|
data/lib/{z_k → zk}/locker.rb
RENAMED
File without changes
|
data/lib/{z_k → zk}/logging.rb
RENAMED
File without changes
|
@@ -13,7 +13,6 @@ module ZK
|
|
13
13
|
# #handle message
|
14
14
|
# end
|
15
15
|
class MessageQueue
|
16
|
-
|
17
16
|
# @private
|
18
17
|
# :nodoc:
|
19
18
|
attr_accessor :zk
|
@@ -79,15 +78,19 @@ module ZK
|
|
79
78
|
# the message
|
80
79
|
def subscribe(&block)
|
81
80
|
@subscription_block = block
|
82
|
-
@
|
81
|
+
@sub = @zk.register(full_queue_path) do |event, zk|
|
83
82
|
find_and_process_next_available(@zk.children(full_queue_path, :watch => true))
|
84
83
|
end
|
84
|
+
|
85
85
|
find_and_process_next_available(@zk.children(full_queue_path, :watch => true))
|
86
86
|
end
|
87
87
|
|
88
88
|
# stop listening to this queue
|
89
89
|
def unsubscribe
|
90
|
-
@
|
90
|
+
if @sub
|
91
|
+
@sub.unsubscribe
|
92
|
+
@sub = nil
|
93
|
+
end
|
91
94
|
end
|
92
95
|
|
93
96
|
# a list of the message titles in the queue
|
@@ -98,6 +101,7 @@ module ZK
|
|
98
101
|
# highly destructive method!
|
99
102
|
# WARNING! Will delete the queue and all messages in it
|
100
103
|
def destroy!
|
104
|
+
unsubscribe # first thing, make sure we don't get any callbacks related to this
|
101
105
|
children = @zk.children(full_queue_path)
|
102
106
|
locks = []
|
103
107
|
children.each do |path|
|
@@ -120,7 +124,7 @@ module ZK
|
|
120
124
|
messages.each do |message_title|
|
121
125
|
message_path = "#{full_queue_path}/#{message_title}"
|
122
126
|
locker = @zk.locker(message_path)
|
123
|
-
if locker.lock!
|
127
|
+
if locker.lock! # non-blocking lock
|
124
128
|
begin
|
125
129
|
data = @zk.get(message_path).first
|
126
130
|
result = @subscription_block.call(message_title, data)
|
data/lib/{z_k → zk}/mongoid.rb
RENAMED
File without changes
|
data/lib/{z_k → zk}/pool.rb
RENAMED
File without changes
|
data/lib/zk/stat.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
module ZK
|
2
|
+
# Included in ZookeeperStat::Stat, extends it with some conveniences for
|
3
|
+
# dealing with Stat objects. Also provides docuemntation here for the meaning
|
4
|
+
# of these values.
|
5
|
+
#
|
6
|
+
# Some of the methods added are to match the names in [the documentation][]
|
7
|
+
#
|
8
|
+
# Some of this may eventually be pushed down to slyphon-zookeeper
|
9
|
+
#
|
10
|
+
# [the documentation]: http://zookeeper.apache.org/doc/r3.3.5/zookeeperProgrammers.html#sc_zkStatStructure
|
11
|
+
module Stat
|
12
|
+
MEMBERS = [:version, :exists, :czxid, :mzxid, :ctime, :mtime, :cversion, :aversion, :ephemeralOwner, :dataLength, :numChildren, :pzxid].freeze
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
MEMBERS.all? { |m| self.__send__(m) == other.__send__(m) }
|
16
|
+
end
|
17
|
+
|
18
|
+
# returns true if the node is ephemeral (will be cleaned up when the
|
19
|
+
# current session expires)
|
20
|
+
def ephemeral?
|
21
|
+
ephemeral_owner && (ephemeral_owner != 0)
|
22
|
+
end
|
23
|
+
|
24
|
+
# The zxid of the change that caused this znode to be created.
|
25
|
+
#
|
26
|
+
# (also: czxid)
|
27
|
+
def created_zxid
|
28
|
+
# @!parse alias czxid created_zxid
|
29
|
+
czxid
|
30
|
+
end
|
31
|
+
|
32
|
+
# The zxid of the change that last modified this znode.
|
33
|
+
#
|
34
|
+
# (also: mzxid)
|
35
|
+
def last_modified_zxid
|
36
|
+
mzxid
|
37
|
+
end
|
38
|
+
|
39
|
+
# The time in milliseconds from epoch when this znode was created
|
40
|
+
#
|
41
|
+
# (also: created\_time)
|
42
|
+
#
|
43
|
+
# @return [Fixnum]
|
44
|
+
# @see #ctime_t
|
45
|
+
def created_time
|
46
|
+
ctime
|
47
|
+
end
|
48
|
+
|
49
|
+
# The time when this znode was created
|
50
|
+
#
|
51
|
+
# @return [Time] creation time of this znode
|
52
|
+
def ctime_t
|
53
|
+
Time.at(ctime * 0.001)
|
54
|
+
end
|
55
|
+
|
56
|
+
# The time in milliseconds from epoch when this znode was last modified.
|
57
|
+
#
|
58
|
+
# (also: mtime)
|
59
|
+
# @return [Fixnum]
|
60
|
+
# @see #mtime_t
|
61
|
+
def last_modified_time
|
62
|
+
mtime
|
63
|
+
end
|
64
|
+
|
65
|
+
# The time when this znode was last modified
|
66
|
+
#
|
67
|
+
# @return [Time] last modification time of this znode
|
68
|
+
# @see #last_modified_time
|
69
|
+
def mtime_t
|
70
|
+
Time.at(mtime * 0.001)
|
71
|
+
end
|
72
|
+
|
73
|
+
# The number of changes to the children of this znode
|
74
|
+
#
|
75
|
+
# (also: #cversion)
|
76
|
+
# @return [Fixnum]
|
77
|
+
def child_list_version
|
78
|
+
cversion
|
79
|
+
end
|
80
|
+
|
81
|
+
# The number of changes to the ACL of this znode.
|
82
|
+
#
|
83
|
+
# (also: #aversion)
|
84
|
+
# @return [Fixnum]
|
85
|
+
def acl_list_version
|
86
|
+
aversion
|
87
|
+
end
|
88
|
+
|
89
|
+
# The number of changes to the data of this znode.
|
90
|
+
#
|
91
|
+
# @return [Fixnum]
|
92
|
+
def version
|
93
|
+
super
|
94
|
+
end
|
95
|
+
|
96
|
+
# The length of the data field of this znode.
|
97
|
+
#
|
98
|
+
# @return [Fixnum]
|
99
|
+
def data_length
|
100
|
+
super
|
101
|
+
end
|
102
|
+
|
103
|
+
# The number of children of this znode.
|
104
|
+
#
|
105
|
+
# @return [Fixnum]
|
106
|
+
def num_children
|
107
|
+
super
|
108
|
+
end
|
109
|
+
end # Stat
|
110
|
+
end # ZK
|
111
|
+
|
112
|
+
class ZookeeperStat::Stat
|
113
|
+
include ZK::Stat
|
114
|
+
end
|
115
|
+
|
@@ -22,6 +22,8 @@ module ZK
|
|
22
22
|
|
23
23
|
@mutex = Mutex.new
|
24
24
|
|
25
|
+
@error_callbacks = []
|
26
|
+
|
25
27
|
start!
|
26
28
|
end
|
27
29
|
|
@@ -35,7 +37,7 @@ module ZK
|
|
35
37
|
callable ||= blk
|
36
38
|
|
37
39
|
# XXX(slyphon): do we care if the threadpool is not running?
|
38
|
-
|
40
|
+
# raise Exceptions::ThreadpoolIsNotRunningException unless running?
|
39
41
|
raise ArgumentError, "Argument to Threadpool#defer must respond_to?(:call)" unless callable.respond_to?(:call)
|
40
42
|
|
41
43
|
@threadqueue << callable
|
@@ -46,6 +48,12 @@ module ZK
|
|
46
48
|
@mutex.synchronize { @running }
|
47
49
|
end
|
48
50
|
|
51
|
+
# returns true if the current thread is one of the threadpool threads
|
52
|
+
def on_threadpool?
|
53
|
+
tp = @mutex.synchronize { @threadpool.dup }
|
54
|
+
tp and tp.respond_to?(:include?) and tp.include?(Thread.current)
|
55
|
+
end
|
56
|
+
|
49
57
|
# starts the threadpool if not already running
|
50
58
|
def start!
|
51
59
|
@mutex.synchronize do
|
@@ -56,6 +64,18 @@ module ZK
|
|
56
64
|
true
|
57
65
|
end
|
58
66
|
|
67
|
+
# register a block to be called back with unhandled exceptions that occur
|
68
|
+
# in the threadpool.
|
69
|
+
#
|
70
|
+
# @note if your exception callback block itself raises an exception, I will
|
71
|
+
# make fun of you.
|
72
|
+
#
|
73
|
+
def on_exception(&blk)
|
74
|
+
@mutex.synchronize do
|
75
|
+
@error_callbacks << blk
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
59
79
|
# join all threads in this threadpool, they will be given a maximum of +timeout+
|
60
80
|
# seconds to exit before they are considered hung and will be ignored (this is an
|
61
81
|
# issue with threads in general: see
|
@@ -90,18 +110,46 @@ module ZK
|
|
90
110
|
end
|
91
111
|
|
92
112
|
private
|
113
|
+
def dispatch_to_error_handler(e)
|
114
|
+
# make a copy that will be free from thread manipulation
|
115
|
+
# and doesn't require holding the lock
|
116
|
+
cbs = @mutex.synchronize { @error_callbacks.dup }
|
117
|
+
|
118
|
+
if cbs.empty?
|
119
|
+
default_exception_handler(e)
|
120
|
+
else
|
121
|
+
while cb = cbs.shift
|
122
|
+
begin
|
123
|
+
cb.call(e)
|
124
|
+
rescue Exception => e
|
125
|
+
msg = [
|
126
|
+
"Exception caught in user supplied on_exception handler.",
|
127
|
+
"Just meditate on the irony of that for a moment. There. Good.",
|
128
|
+
"The callback that errored was: #{cb.inspect}, the exception was",
|
129
|
+
""
|
130
|
+
]
|
131
|
+
|
132
|
+
default_exception_handler(e, msg.join("\n"))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def default_exception_handler(e, msg=nil)
|
139
|
+
msg ||= 'Exception caught in threadpool'
|
140
|
+
logger.error { "#{msg}: #{e.to_std_format}" }
|
141
|
+
end
|
142
|
+
|
93
143
|
def spawn_threadpool #:nodoc:
|
94
144
|
until @threadpool.size >= @size.to_i
|
95
145
|
thread = Thread.new do
|
96
146
|
while @running
|
97
147
|
begin
|
98
148
|
op = @threadqueue.pop
|
99
|
-
# $stderr.puts "thread #{Thread.current.inspect} got #{op.inspect}"
|
100
149
|
break if op == KILL_TOKEN
|
101
150
|
op.call
|
102
151
|
rescue Exception => e
|
103
|
-
|
104
|
-
logger.error { e.to_std_format }
|
152
|
+
dispatch_to_error_handler(e)
|
105
153
|
end
|
106
154
|
end
|
107
155
|
end
|
data/lib/zk/version.rb
ADDED