celluloid 0.17.2 → 0.18.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.
Files changed (174) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +340 -75
  3. data/CONDUCT.md +13 -0
  4. data/CONTRIBUTING.md +39 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.md +54 -150
  7. data/REFACTOR.md +1 -0
  8. data/architecture.md +120 -0
  9. data/examples/basic_usage.rb +1 -1
  10. data/examples/configurations.rb +78 -0
  11. data/examples/futures.rb +1 -1
  12. data/examples/ring.rb +5 -4
  13. data/examples/simple_pmap.rb +1 -1
  14. data/examples/stack.rb +2 -2
  15. data/examples/supervisors_and_registry.rb +82 -0
  16. data/examples/timers.rb +2 -2
  17. data/lib/celluloid.rb +78 -65
  18. data/lib/celluloid/actor.rb +27 -17
  19. data/lib/celluloid/actor/system.rb +13 -29
  20. data/lib/celluloid/autostart.rb +6 -1
  21. data/lib/celluloid/call/async.rb +2 -0
  22. data/lib/celluloid/call/sync.rb +10 -3
  23. data/lib/celluloid/calls.rb +13 -13
  24. data/lib/celluloid/cell.rb +5 -9
  25. data/lib/celluloid/condition.rb +3 -3
  26. data/lib/celluloid/core_ext.rb +0 -2
  27. data/lib/celluloid/debug.rb +3 -0
  28. data/lib/celluloid/exceptions.rb +2 -2
  29. data/lib/celluloid/future.rb +8 -10
  30. data/lib/celluloid/group.rb +16 -6
  31. data/lib/celluloid/group/pool.rb +1 -3
  32. data/lib/celluloid/group/spawner.rb +2 -6
  33. data/lib/celluloid/internals/call_chain.rb +15 -0
  34. data/lib/celluloid/internals/cpu_counter.rb +62 -0
  35. data/lib/celluloid/internals/handlers.rb +42 -0
  36. data/lib/celluloid/internals/links.rb +38 -0
  37. data/lib/celluloid/internals/logger.rb +104 -0
  38. data/lib/celluloid/internals/method.rb +34 -0
  39. data/lib/celluloid/internals/properties.rb +32 -0
  40. data/lib/celluloid/internals/receivers.rb +64 -0
  41. data/lib/celluloid/internals/registry.rb +102 -0
  42. data/lib/celluloid/internals/responses.rb +46 -0
  43. data/lib/celluloid/internals/signals.rb +24 -0
  44. data/lib/celluloid/internals/stack.rb +74 -0
  45. data/lib/celluloid/internals/stack/dump.rb +12 -0
  46. data/lib/celluloid/internals/stack/states.rb +72 -0
  47. data/lib/celluloid/internals/stack/summary.rb +12 -0
  48. data/lib/celluloid/internals/task_set.rb +51 -0
  49. data/lib/celluloid/internals/thread_handle.rb +52 -0
  50. data/lib/celluloid/internals/uuid.rb +40 -0
  51. data/lib/celluloid/logging/incident.rb +21 -0
  52. data/lib/celluloid/logging/incident_logger.rb +147 -0
  53. data/lib/celluloid/logging/incident_reporter.rb +49 -0
  54. data/lib/celluloid/logging/log_event.rb +20 -0
  55. data/lib/celluloid/logging/ring_buffer.rb +64 -0
  56. data/lib/celluloid/mailbox.rb +22 -9
  57. data/lib/celluloid/mailbox/evented.rb +13 -7
  58. data/lib/celluloid/notifications.rb +95 -0
  59. data/lib/celluloid/pool.rb +6 -0
  60. data/lib/celluloid/probe.rb +81 -0
  61. data/lib/celluloid/proxy/abstract.rb +38 -7
  62. data/lib/celluloid/proxy/actor.rb +0 -5
  63. data/lib/celluloid/proxy/async.rb +2 -18
  64. data/lib/celluloid/proxy/block.rb +2 -1
  65. data/lib/celluloid/proxy/cell.rb +1 -7
  66. data/lib/celluloid/proxy/future.rb +3 -21
  67. data/lib/celluloid/proxy/sync.rb +2 -20
  68. data/lib/celluloid/rspec.rb +22 -34
  69. data/lib/celluloid/supervision.rb +17 -0
  70. data/lib/celluloid/supervision/configuration.rb +169 -0
  71. data/lib/celluloid/supervision/configuration/injections.rb +8 -0
  72. data/lib/celluloid/supervision/configuration/instance.rb +113 -0
  73. data/lib/celluloid/supervision/constants.rb +123 -0
  74. data/lib/celluloid/supervision/container.rb +144 -0
  75. data/lib/celluloid/supervision/container/behavior.rb +89 -0
  76. data/lib/celluloid/supervision/container/behavior/pool.rb +71 -0
  77. data/lib/celluloid/supervision/container/behavior/tree.rb +23 -0
  78. data/lib/celluloid/supervision/container/injections.rb +8 -0
  79. data/lib/celluloid/supervision/container/instance.rb +116 -0
  80. data/lib/celluloid/supervision/container/pool.rb +210 -0
  81. data/lib/celluloid/supervision/service.rb +27 -0
  82. data/lib/celluloid/supervision/supervise.rb +34 -0
  83. data/lib/celluloid/supervision/validation.rb +40 -0
  84. data/lib/celluloid/supervision/version.rb +5 -0
  85. data/lib/celluloid/system_events.rb +10 -3
  86. data/lib/celluloid/task.rb +25 -12
  87. data/lib/celluloid/task/fibered.rb +6 -2
  88. data/lib/celluloid/task/threaded.rb +3 -3
  89. data/lib/celluloid/test.rb +5 -2
  90. data/lib/celluloid/thread.rb +0 -2
  91. data/lib/celluloid/version.rb +1 -1
  92. data/spec/celluloid/block_spec.rb +29 -32
  93. data/spec/celluloid/calls_spec.rb +5 -15
  94. data/spec/celluloid/future_spec.rb +7 -1
  95. data/spec/celluloid/internals/cpu_counter_spec.rb +129 -0
  96. data/spec/celluloid/internals/links_spec.rb +43 -0
  97. data/spec/celluloid/internals/properties_spec.rb +40 -0
  98. data/spec/celluloid/internals/registry_spec.rb +62 -0
  99. data/spec/celluloid/internals/stack/dump_spec.rb +4 -0
  100. data/spec/celluloid/internals/stack/summary_spec.rb +4 -0
  101. data/spec/celluloid/internals/thread_handle_spec.rb +60 -0
  102. data/spec/celluloid/internals/uuid_spec.rb +9 -0
  103. data/spec/celluloid/logging/ring_buffer_spec.rb +36 -0
  104. data/spec/celluloid/mailbox/evented_spec.rb +21 -19
  105. data/spec/celluloid/misc/leak_spec.rb +3 -4
  106. data/spec/celluloid/notifications_spec.rb +140 -0
  107. data/spec/celluloid/probe_spec.rb +102 -0
  108. data/spec/celluloid/proxy_spec.rb +33 -0
  109. data/spec/celluloid/supervision/behavior_spec.rb +74 -0
  110. data/spec/celluloid/supervision/configuration_spec.rb +181 -0
  111. data/spec/celluloid/supervision/container_spec.rb +72 -0
  112. data/spec/celluloid/supervision/instance_spec.rb +13 -0
  113. data/spec/celluloid/supervision/root_spec.rb +28 -0
  114. data/spec/celluloid/supervision/supervisor_spec.rb +93 -0
  115. data/spec/celluloid/task/fibered_spec.rb +1 -3
  116. data/spec/celluloid/task/threaded_spec.rb +1 -3
  117. data/spec/shared/actor_examples.rb +65 -29
  118. data/spec/shared/group_examples.rb +2 -2
  119. data/spec/shared/mailbox_examples.rb +1 -1
  120. data/spec/shared/stack_examples.rb +87 -0
  121. data/spec/shared/task_examples.rb +2 -3
  122. data/spec/spec_helper.rb +2 -4
  123. data/spec/support/configure_rspec.rb +3 -4
  124. data/spec/support/coverage.rb +2 -4
  125. data/spec/support/crash_checking.rb +2 -2
  126. data/spec/support/examples/actor_class.rb +3 -8
  127. data/spec/support/examples/call_class.rb +2 -2
  128. data/spec/support/examples/container_class.rb +35 -0
  129. data/spec/support/examples/evented_mailbox_class.rb +1 -2
  130. data/spec/support/examples/stack_classes.rb +58 -0
  131. data/spec/support/examples/stack_methods.rb +23 -0
  132. data/spec/support/examples/subordinate_class.rb +19 -0
  133. data/spec/support/logging.rb +3 -34
  134. data/spec/support/loose_threads.rb +3 -24
  135. data/spec/support/reset_class_variables.rb +5 -1
  136. data/spec/support/stubbing.rb +1 -1
  137. metadata +93 -291
  138. data/culture/CONDUCT.md +0 -28
  139. data/culture/Gemfile +0 -9
  140. data/culture/LICENSE.txt +0 -22
  141. data/culture/README.md +0 -22
  142. data/culture/Rakefile +0 -5
  143. data/culture/SYNC.md +0 -70
  144. data/culture/celluloid-culture.gemspec +0 -18
  145. data/culture/gems/README.md +0 -39
  146. data/culture/gems/dependencies.yml +0 -85
  147. data/culture/gems/loader.rb +0 -101
  148. data/culture/rubocop/README.md +0 -38
  149. data/culture/rubocop/lint.yml +0 -8
  150. data/culture/rubocop/metrics.yml +0 -15
  151. data/culture/rubocop/perf.yml +0 -0
  152. data/culture/rubocop/rubocop.yml +0 -5
  153. data/culture/rubocop/style.yml +0 -57
  154. data/culture/spec/gems_spec.rb +0 -2
  155. data/culture/spec/spec_helper.rb +0 -0
  156. data/culture/spec/sync_spec.rb +0 -2
  157. data/culture/sync.rb +0 -56
  158. data/culture/tasks/rspec.rake +0 -5
  159. data/culture/tasks/rubocop.rake +0 -2
  160. data/lib/celluloid/actor/manager.rb +0 -7
  161. data/lib/celluloid/backported.rb +0 -2
  162. data/lib/celluloid/current.rb +0 -2
  163. data/lib/celluloid/deprecate.rb +0 -21
  164. data/lib/celluloid/fiber.rb +0 -32
  165. data/lib/celluloid/managed.rb +0 -3
  166. data/lib/celluloid/notices.rb +0 -15
  167. data/spec/celluloid/actor/manager_spec.rb +0 -0
  168. data/spec/deprecate/actor_system_spec.rb +0 -72
  169. data/spec/deprecate/block_spec.rb +0 -52
  170. data/spec/deprecate/calls_spec.rb +0 -39
  171. data/spec/deprecate/evented_mailbox_spec.rb +0 -34
  172. data/spec/deprecate/future_spec.rb +0 -32
  173. data/spec/deprecate/internal_pool_spec.rb +0 -4
  174. data/spec/support/env.rb +0 -21
@@ -0,0 +1,89 @@
1
+ module Celluloid
2
+ module Supervision
3
+ class Container
4
+ module Behavior
5
+ @@injections = {} # Hash of Class => Hash of Injections
6
+ @@behaviors = {} # Hash of identifying symbol parameter => Class
7
+
8
+ module Error
9
+ class Mutant < Celluloid::Error; end
10
+ end
11
+
12
+ class << self
13
+ def included(klass)
14
+ klass.send :extend, ClassMethods
15
+ end
16
+
17
+ def injections
18
+ @@injections
19
+ end
20
+
21
+ def [](identifier)
22
+ @@behaviors[identifier]
23
+ end
24
+
25
+ def []=(identifier, behavior)
26
+ @@behaviors[identifier] = behavior
27
+ end
28
+
29
+ def parameter(identifier, options)
30
+ found = nil
31
+ p = Configuration.aliases.each_with_object([identifier]) { |(a, i), invoke| invoke << a if i == identifier; }
32
+ case p.count { |parameter| found = parameter; options.key?(parameter) }
33
+ when 1
34
+ found
35
+ when 0
36
+
37
+ else
38
+ raise Error::Mutant, "More than one kind of identifiable behavior parameter."
39
+ end
40
+ end
41
+
42
+ # Beware of order. There may be multiple behavior injections, but their order is not determined ( yet )
43
+ # Right now, something like a pool-coordinator-tree supervisor mutant are absolutely expected to crash.
44
+ # Therefore, sorry Professor X -- we kill every Mutant. On sight, no questions asked. Zero mutant love.
45
+ def configure(options)
46
+ behavior = nil
47
+ injection = nil
48
+ @@behaviors.map do |identifier, injector|
49
+ if identifier = parameter(identifier, options)
50
+ if behavior
51
+ raise Error::Mutant, "More than one type of behavior expected."
52
+ else
53
+ if @@injections[injector].include?(:configuration)
54
+ injection = @@injections[behavior = injector][:configuration]
55
+ options[:behavior] ||= behavior
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ options[:type] ||= behavior
62
+ injection || proc { @configuration }
63
+ end
64
+
65
+ module ClassMethods
66
+ def identifier!(identifier, *aliases)
67
+ Behavior[identifier] = self
68
+ Configuration.parameter! :plugins, identifier
69
+ aliases.each do |aliased|
70
+ Configuration.alias! aliased, identifier
71
+ end
72
+ Configuration.save_defaults
73
+ end
74
+
75
+ def behavior_injections
76
+ Behavior.injections[self] ||= {}
77
+ end
78
+
79
+ Configuration::INJECTIONS.each do |point|
80
+ define_method(point) do |&injector|
81
+ behavior_injections[point] = injector
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,71 @@
1
+ require "set"
2
+
3
+ module Celluloid
4
+ module ClassMethods
5
+ extend Forwardable
6
+ def_delegators :"Celluloid::Supervision::Container::Pool", :pooling_options
7
+ # Create a new pool of workers. Accepts the following options:
8
+ #
9
+ # * size: how many workers to create. Default is worker per CPU core
10
+ # * args: array of arguments to pass when creating a worker
11
+ #
12
+ def pool(config = {}, &block)
13
+ _ = Celluloid.supervise(pooling_options(config, block: block, actors: self))
14
+ _.actors.last
15
+ end
16
+
17
+ # Same as pool, but links to the pool manager
18
+ def pool_link(klass, config = {}, &block)
19
+ Supervision::Container::Pool.new_link(pooling_options(config, block: block, actors: klass))
20
+ end
21
+ end
22
+
23
+ module Supervision
24
+ class Container
25
+ extend Forwardable
26
+ def_delegators :"Celluloid::Supervision::Container::Pool", :pooling_options
27
+
28
+ def pool(klass, config = {}, &block)
29
+ _ = supervise(pooling_options(config, block: block, actors: klass))
30
+ _.actors.last
31
+ end
32
+
33
+ class Instance
34
+ attr_accessor :pool, :pool_size
35
+ end
36
+
37
+ class << self
38
+ # Register a pool of actors to be launched on group startup
39
+ def pool(klass, config, &block)
40
+ blocks << lambda do |container|
41
+ container.pool(klass, config, &block)
42
+ end
43
+ end
44
+ end
45
+
46
+ class Pool
47
+ include Behavior
48
+
49
+ class << self
50
+ def pooling_options(config = {}, mixins = {})
51
+ combined = { type: Celluloid::Supervision::Container::Pool }.merge(config).merge(mixins)
52
+ combined[:args] = [%i[block actors size args].each_with_object({}) do |p, e|
53
+ e[p] = combined.delete(p) if combined[p]
54
+ end]
55
+ combined
56
+ end
57
+ end
58
+
59
+ identifier! :size, :pool
60
+
61
+ configuration do
62
+ @supervisor = Container::Pool
63
+ @method = "pool_link"
64
+ @pool = true
65
+ @pool_size = @configuration[:size]
66
+ @configuration
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,23 @@
1
+ module Celluloid
2
+ module Supervision
3
+ class Container
4
+ class Tree
5
+ include Behavior
6
+
7
+ identifier! :supervises, :supervise
8
+
9
+ configuration do
10
+ if @configuration[:supervise].is_a? Array
11
+ @supervisor = @configuration.dup
12
+ @branch = @configuration.fetch(:branch, @configuration[:as])
13
+ @configuration.delete(Behavior.parameter(:supervise, @configuration))
14
+ elsif @configuration[:supervise].is_a?(Celluloid::Supervision::Configuration)
15
+ @configuration
16
+ else
17
+ raise ArgumentError, "No actors given to Tree to supervise."
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ module Celluloid
2
+ module Supervision
3
+ class Container
4
+ class Injection
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,116 @@
1
+ module Celluloid
2
+ # Supervise collections of actors as a group
3
+ module Supervision
4
+ class Container
5
+ class Instance
6
+ attr_reader :name, :actor
7
+
8
+ # @option options [#call, Object] :args ([]) arguments array for the
9
+ # actor's constructor (lazy evaluation if it responds to #call)
10
+ def initialize(configuration = {})
11
+ @type = configuration.delete(:type)
12
+ @registry = configuration.delete(:registry)
13
+ @branch = configuration.delete(:branch) || :services
14
+ @configuration = configuration
15
+
16
+ # allows injections inside initialize, start, and restart
17
+ @injections = configuration.delete(:injections) || {}
18
+ invoke_injection(:before_initialize)
19
+
20
+ # Stringify keys :/
21
+ # de @configuration = configuration.each_with_object({}) { |(k,v), h| h[k.to_s] = v }
22
+
23
+ @name = @configuration[:as]
24
+ @block = @configuration[:block]
25
+ @args = prepare_args(@configuration[:args])
26
+ @method = @configuration[:method] || "new_link"
27
+ add_accessors
28
+ invoke_injection(:after_initialize)
29
+ start
30
+ end
31
+
32
+ def start
33
+ invoke_injection(:before_start)
34
+ @actor = @type.send(@method, *@args, &@block)
35
+ @registry.add(@name, @actor, @branch) if @name
36
+ invoke_injection(:after_start)
37
+ rescue Celluloid::TaskTimeout => ex
38
+ Internals::Logger.error("TaskTimeout at start of supervised instance of #{@type}")
39
+ raise ex
40
+ # TODO: Implement timeout/retry(?)
41
+ rescue => ex
42
+ Internals::Logger.error("Error ( #{ex.class} ) at start of supervised instance of #{@type}")
43
+ raise ex
44
+ end
45
+
46
+ def restart
47
+ # no need to reset @actor, as this is called in an `exclusive {}` block
48
+ # @actor = nil
49
+ # cleanup
50
+ invoke_injection(:before_restart)
51
+ start
52
+ invoke_injection(:after_restart)
53
+ end
54
+
55
+ def terminate
56
+ @actor.terminate if @actor
57
+ cleanup
58
+ rescue DeadActorError
59
+ end
60
+
61
+ def cleanup
62
+ @registry.delete(@name) if @name
63
+ end
64
+
65
+ private
66
+
67
+ def add_accessors
68
+ remove_accessors
69
+ if @configuration[:accessors].is_a? Array
70
+ # TODO: Decide which level to keep, and only keep that.
71
+ # Do we provide access by Celluloid.accessor
72
+ # Do we provide access by Celluloid.actor_system.accessor
73
+ @configuration[:accessors].each do |name|
74
+ Celluloid.instance_exec(@configuration[:as], name) do |actor, _where|
75
+ define_method(name) do
76
+ Celluloid.actor_system[actor]
77
+ end
78
+ end
79
+ Celluloid::Actor::System.instance_exec(@configuration[:as], name) do |actor, _where|
80
+ define_method(name) do
81
+ Celluloid.actor_system[actor]
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def remove_accessors
89
+ if @configuration[:accessors].is_a? Array
90
+ @configuration[:accessors].each do |name|
91
+ Celluloid.instance_eval do
92
+ remove_method(name) rescue nil # avoid warnings in tests
93
+ end
94
+ Celluloid::Actor::System.instance_eval do
95
+ remove_method(name) rescue nil # avoid warnings in tests
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ def invoke_injection(name)
102
+ return unless @injections
103
+ block = @injections[name]
104
+ instance_eval(&block) if block.is_a? Proc
105
+ end
106
+
107
+ # Executes args if it has the method #call, and converts the return
108
+ # value to an Array. Otherwise, it just converts it to an Array.
109
+ def prepare_args(args)
110
+ args = args.call if args.respond_to?(:call)
111
+ Array(args)
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,210 @@
1
+ module Celluloid
2
+ module Supervision
3
+ class Container
4
+ # Manages a fixed-size pool of actors
5
+ # Delegates work (i.e. methods) and supervises actors
6
+ # Don't use this class directly. Instead use MyKlass.pool
7
+ class Pool
8
+ include Celluloid
9
+
10
+ trap_exit :__crash_handler__
11
+ finalizer :__shutdown__
12
+
13
+ attr_reader :size, :actors
14
+
15
+ def initialize(options = {})
16
+ @idle = []
17
+ @busy = []
18
+ @klass = options[:actors]
19
+ @actors = Set.new
20
+ @mutex = Mutex.new
21
+
22
+ @size = options[:size] || [Celluloid.cores || 2, 2].max
23
+ @args = options[:args] ? Array(options[:args]) : []
24
+
25
+ # Do this last since it can suspend and/or crash
26
+ @idle = @size.times.map { __spawn_actor__ }
27
+ end
28
+
29
+ def __shutdown__
30
+ return unless defined?(@actors) && @actors
31
+ # TODO: these can be nil if initializer crashes
32
+ terminators = @actors.map do |actor|
33
+ begin
34
+ actor.future(:terminate)
35
+ rescue DeadActorError
36
+ end
37
+ end
38
+
39
+ terminators.compact.each { |terminator| terminator.value rescue nil }
40
+ end
41
+
42
+ def _send_(method, *args, &block)
43
+ actor = __provision_actor__
44
+ begin
45
+ actor._send_ method, *args, &block
46
+ rescue DeadActorError # if we get a dead actor out of the pool
47
+ wait :respawn_complete
48
+ actor = __provision_actor__
49
+ retry
50
+ rescue ::Exception => ex
51
+ abort ex
52
+ ensure
53
+ if actor.alive?
54
+ @idle << actor
55
+ @busy.delete actor
56
+
57
+ # Broadcast that actor is done processing and
58
+ # waiting idle
59
+ signal :actor_idle
60
+ end
61
+ end
62
+ end
63
+
64
+ def name
65
+ _send_ @mailbox, :name
66
+ end
67
+
68
+ def is_a?(klass)
69
+ _send_ :is_a?, klass
70
+ end
71
+
72
+ def kind_of?(klass)
73
+ _send_ :kind_of?, klass
74
+ end
75
+
76
+ def methods(include_ancestors = true)
77
+ _send_ :methods, include_ancestors
78
+ end
79
+
80
+ def to_s
81
+ _send_ :to_s
82
+ end
83
+
84
+ def inspect
85
+ _send_ :inspect
86
+ end
87
+
88
+ def size=(new_size)
89
+ new_size = [0, new_size].max
90
+ if new_size > size
91
+ delta = new_size - size
92
+ delta.times { @idle << __spawn_actor__ }
93
+ else
94
+ (size - new_size).times do
95
+ actor = __provision_actor__
96
+ unlink actor
97
+ @busy.delete actor
98
+ @actors.delete actor
99
+ actor.terminate
100
+ end
101
+ end
102
+ @size = new_size
103
+ end
104
+
105
+ def busy_size
106
+ @mutex.synchronize { @busy.length }
107
+ end
108
+
109
+ def idle_size
110
+ @mutex.synchronize { @idle.length }
111
+ end
112
+
113
+ def __idle?(actor)
114
+ @mutex.synchronize { @idle.include? actor }
115
+ end
116
+
117
+ def __busy?(actor)
118
+ @mutex.synchronize { @busy.include? actor }
119
+ end
120
+
121
+ def __busy
122
+ @mutex.synchronize { @busy }
123
+ end
124
+
125
+ def __idle
126
+ @mutex.synchronize { @idle }
127
+ end
128
+
129
+ def __state(actor)
130
+ return :busy if __busy?(actor)
131
+ return :idle if __idle?(actor)
132
+ :missing
133
+ end
134
+
135
+ # Instantiate an actor, add it to the actor Set, and return it
136
+ def __spawn_actor__
137
+ actor = @klass.new_link(*@args)
138
+ @mutex.synchronize { @actors.add(actor) }
139
+ @actors.add(actor)
140
+ actor
141
+ end
142
+
143
+ # Provision a new actor ( take it out of idle, move it into busy, and avail it )
144
+ def __provision_actor__
145
+ Task.current.guard_warnings = true
146
+ @mutex.synchronize do
147
+ while @idle.empty?
148
+ # Wait for responses from one of the busy actors
149
+ response = exclusive { receive { |msg| msg.is_a?(Internals::Response) } }
150
+ Thread.current[:celluloid_actor].handle_message(response)
151
+ end
152
+
153
+ actor = @idle.shift
154
+ @busy << actor
155
+ actor
156
+ end
157
+ end
158
+
159
+ # Spawn a new worker for every crashed one
160
+ def __crash_handler__(actor, reason)
161
+ @busy.delete actor
162
+ @idle.delete actor
163
+ @actors.delete actor
164
+ return unless reason
165
+ @idle << __spawn_actor__
166
+ signal :respawn_complete
167
+ end
168
+
169
+ def respond_to?(meth, include_private = false)
170
+ # NOTE: use method() here since this class
171
+ # shouldn't be used directly, and method() is less
172
+ # likely to be "reimplemented" inconsistently
173
+ # with other Object.*method* methods.
174
+
175
+ found = method(meth)
176
+ if include_private
177
+ found ? true : false
178
+ else
179
+ if found.is_a?(UnboundMethod)
180
+ found.owner.public_instance_methods.include?(meth) ||
181
+ found.owner.protected_instance_methods.include?(meth)
182
+ else
183
+ found.receiver.public_methods.include?(meth) ||
184
+ found.receiver.protected_methods.include?(meth)
185
+ end
186
+ end
187
+ rescue NameError
188
+ false
189
+ end
190
+
191
+ def method_missing(method, *args, &block)
192
+ if respond_to?(method)
193
+ _send_ method, *args, &block
194
+ else
195
+ super
196
+ end
197
+ end
198
+
199
+ # Since Pool allocates worker objects only just before calling them,
200
+ # we can still help Celluloid::Call detect passing invalid parameters to
201
+ # async methods by checking for those methods on the worker class
202
+ def method(meth)
203
+ super
204
+ rescue NameError
205
+ @klass.instance_method(meth.to_sym)
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end