celluloid 0.17.4 → 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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +300 -81
  3. data/CONDUCT.md +13 -0
  4. data/CONTRIBUTING.md +39 -0
  5. data/README.md +54 -155
  6. data/REFACTOR.md +1 -0
  7. data/architecture.md +120 -0
  8. data/examples/basic_usage.rb +1 -1
  9. data/examples/configurations.rb +78 -0
  10. data/examples/futures.rb +1 -1
  11. data/examples/ring.rb +5 -4
  12. data/examples/simple_pmap.rb +1 -1
  13. data/examples/stack.rb +2 -2
  14. data/examples/supervisors_and_registry.rb +82 -0
  15. data/examples/timers.rb +2 -2
  16. data/lib/celluloid/actor/system.rb +13 -29
  17. data/lib/celluloid/actor.rb +27 -17
  18. data/lib/celluloid/autostart.rb +6 -1
  19. data/lib/celluloid/call/async.rb +2 -0
  20. data/lib/celluloid/call/sync.rb +10 -3
  21. data/lib/celluloid/calls.rb +13 -12
  22. data/lib/celluloid/cell.rb +5 -9
  23. data/lib/celluloid/condition.rb +3 -3
  24. data/lib/celluloid/core_ext.rb +0 -2
  25. data/lib/celluloid/debug.rb +3 -0
  26. data/lib/celluloid/exceptions.rb +2 -2
  27. data/lib/celluloid/future.rb +8 -10
  28. data/lib/celluloid/group/pool.rb +1 -3
  29. data/lib/celluloid/group/spawner.rb +2 -6
  30. data/lib/celluloid/group.rb +12 -8
  31. data/lib/celluloid/internals/call_chain.rb +15 -0
  32. data/lib/celluloid/internals/cpu_counter.rb +62 -0
  33. data/lib/celluloid/internals/handlers.rb +42 -0
  34. data/lib/celluloid/internals/links.rb +38 -0
  35. data/lib/celluloid/internals/logger.rb +104 -0
  36. data/lib/celluloid/internals/method.rb +34 -0
  37. data/lib/celluloid/internals/properties.rb +32 -0
  38. data/lib/celluloid/internals/receivers.rb +64 -0
  39. data/lib/celluloid/internals/registry.rb +102 -0
  40. data/lib/celluloid/internals/responses.rb +46 -0
  41. data/lib/celluloid/internals/signals.rb +24 -0
  42. data/lib/celluloid/internals/stack/dump.rb +12 -0
  43. data/lib/celluloid/internals/stack/states.rb +72 -0
  44. data/lib/celluloid/internals/stack/summary.rb +12 -0
  45. data/lib/celluloid/internals/stack.rb +74 -0
  46. data/lib/celluloid/internals/task_set.rb +51 -0
  47. data/lib/celluloid/internals/thread_handle.rb +52 -0
  48. data/lib/celluloid/internals/uuid.rb +40 -0
  49. data/lib/celluloid/logging/incident.rb +21 -0
  50. data/lib/celluloid/logging/incident_logger.rb +147 -0
  51. data/lib/celluloid/logging/incident_reporter.rb +49 -0
  52. data/lib/celluloid/logging/log_event.rb +20 -0
  53. data/lib/celluloid/logging/ring_buffer.rb +64 -0
  54. data/lib/celluloid/mailbox/evented.rb +13 -5
  55. data/lib/celluloid/mailbox.rb +22 -9
  56. data/lib/celluloid/notifications.rb +95 -0
  57. data/lib/celluloid/pool.rb +6 -0
  58. data/lib/celluloid/probe.rb +81 -0
  59. data/lib/celluloid/proxy/abstract.rb +9 -9
  60. data/lib/celluloid/proxy/async.rb +1 -1
  61. data/lib/celluloid/proxy/block.rb +2 -2
  62. data/lib/celluloid/proxy/cell.rb +1 -1
  63. data/lib/celluloid/proxy/future.rb +2 -4
  64. data/lib/celluloid/proxy/sync.rb +1 -3
  65. data/lib/celluloid/rspec.rb +22 -33
  66. data/lib/celluloid/supervision/configuration/injections.rb +8 -0
  67. data/lib/celluloid/supervision/configuration/instance.rb +113 -0
  68. data/lib/celluloid/supervision/configuration.rb +169 -0
  69. data/lib/celluloid/supervision/constants.rb +123 -0
  70. data/lib/celluloid/supervision/container/behavior/pool.rb +71 -0
  71. data/lib/celluloid/supervision/container/behavior/tree.rb +23 -0
  72. data/lib/celluloid/supervision/container/behavior.rb +89 -0
  73. data/lib/celluloid/supervision/container/injections.rb +8 -0
  74. data/lib/celluloid/supervision/container/instance.rb +116 -0
  75. data/lib/celluloid/supervision/container/pool.rb +210 -0
  76. data/lib/celluloid/supervision/container.rb +144 -0
  77. data/lib/celluloid/supervision/service.rb +27 -0
  78. data/lib/celluloid/supervision/supervise.rb +34 -0
  79. data/lib/celluloid/supervision/validation.rb +40 -0
  80. data/lib/celluloid/supervision/version.rb +5 -0
  81. data/lib/celluloid/supervision.rb +17 -0
  82. data/lib/celluloid/system_events.rb +11 -6
  83. data/lib/celluloid/task/fibered.rb +6 -2
  84. data/lib/celluloid/task/threaded.rb +3 -3
  85. data/lib/celluloid/task.rb +25 -12
  86. data/lib/celluloid/test.rb +5 -2
  87. data/lib/celluloid/thread.rb +0 -2
  88. data/lib/celluloid/version.rb +1 -1
  89. data/lib/celluloid.rb +74 -64
  90. data/spec/celluloid/block_spec.rb +29 -32
  91. data/spec/celluloid/calls_spec.rb +5 -15
  92. data/spec/celluloid/future_spec.rb +7 -1
  93. data/spec/celluloid/internals/cpu_counter_spec.rb +129 -0
  94. data/spec/celluloid/internals/links_spec.rb +43 -0
  95. data/spec/celluloid/internals/properties_spec.rb +40 -0
  96. data/spec/celluloid/internals/registry_spec.rb +62 -0
  97. data/spec/celluloid/internals/stack/dump_spec.rb +4 -0
  98. data/spec/celluloid/internals/stack/summary_spec.rb +4 -0
  99. data/spec/celluloid/internals/thread_handle_spec.rb +60 -0
  100. data/spec/celluloid/internals/uuid_spec.rb +9 -0
  101. data/spec/celluloid/logging/ring_buffer_spec.rb +36 -0
  102. data/spec/celluloid/mailbox/evented_spec.rb +11 -22
  103. data/spec/celluloid/misc/leak_spec.rb +3 -4
  104. data/spec/celluloid/notifications_spec.rb +140 -0
  105. data/spec/celluloid/probe_spec.rb +102 -0
  106. data/spec/celluloid/proxy_spec.rb +30 -30
  107. data/spec/celluloid/supervision/behavior_spec.rb +74 -0
  108. data/spec/celluloid/supervision/configuration_spec.rb +181 -0
  109. data/spec/celluloid/supervision/container_spec.rb +72 -0
  110. data/spec/celluloid/supervision/instance_spec.rb +13 -0
  111. data/spec/celluloid/supervision/root_spec.rb +28 -0
  112. data/spec/celluloid/supervision/supervisor_spec.rb +93 -0
  113. data/spec/celluloid/task/fibered_spec.rb +1 -3
  114. data/spec/celluloid/task/threaded_spec.rb +1 -3
  115. data/spec/shared/actor_examples.rb +58 -33
  116. data/spec/shared/group_examples.rb +2 -2
  117. data/spec/shared/mailbox_examples.rb +1 -1
  118. data/spec/shared/stack_examples.rb +87 -0
  119. data/spec/shared/task_examples.rb +2 -3
  120. data/spec/spec_helper.rb +2 -4
  121. data/spec/support/configure_rspec.rb +2 -3
  122. data/spec/support/coverage.rb +2 -4
  123. data/spec/support/crash_checking.rb +2 -2
  124. data/spec/support/examples/actor_class.rb +3 -8
  125. data/spec/support/examples/call_class.rb +2 -2
  126. data/spec/support/examples/container_class.rb +35 -0
  127. data/spec/support/examples/evented_mailbox_class.rb +1 -2
  128. data/spec/support/examples/stack_classes.rb +58 -0
  129. data/spec/support/examples/stack_methods.rb +23 -0
  130. data/spec/support/examples/subordinate_class.rb +19 -0
  131. data/spec/support/logging.rb +3 -34
  132. data/spec/support/loose_threads.rb +3 -16
  133. data/spec/support/reset_class_variables.rb +5 -1
  134. data/spec/support/stubbing.rb +1 -1
  135. metadata +91 -289
  136. data/culture/CONDUCT.md +0 -28
  137. data/culture/Gemfile +0 -9
  138. data/culture/LICENSE.txt +0 -22
  139. data/culture/README.md +0 -22
  140. data/culture/Rakefile +0 -5
  141. data/culture/SYNC.md +0 -70
  142. data/culture/celluloid-culture.gemspec +0 -18
  143. data/culture/gems/README.md +0 -39
  144. data/culture/gems/dependencies.yml +0 -85
  145. data/culture/gems/loader.rb +0 -101
  146. data/culture/rubocop/README.md +0 -38
  147. data/culture/rubocop/lint.yml +0 -8
  148. data/culture/rubocop/metrics.yml +0 -15
  149. data/culture/rubocop/perf.yml +0 -0
  150. data/culture/rubocop/rubocop.yml +0 -5
  151. data/culture/rubocop/style.yml +0 -57
  152. data/culture/spec/gems_spec.rb +0 -2
  153. data/culture/spec/spec_helper.rb +0 -0
  154. data/culture/spec/sync_spec.rb +0 -2
  155. data/culture/sync.rb +0 -56
  156. data/culture/tasks/rspec.rake +0 -5
  157. data/culture/tasks/rubocop.rake +0 -2
  158. data/lib/celluloid/actor/manager.rb +0 -7
  159. data/lib/celluloid/backported.rb +0 -2
  160. data/lib/celluloid/current.rb +0 -2
  161. data/lib/celluloid/deprecate.rb +0 -21
  162. data/lib/celluloid/fiber.rb +0 -32
  163. data/lib/celluloid/managed.rb +0 -3
  164. data/lib/celluloid/notices.rb +0 -15
  165. data/spec/deprecate/actor_system_spec.rb +0 -72
  166. data/spec/deprecate/block_spec.rb +0 -52
  167. data/spec/deprecate/calls_spec.rb +0 -39
  168. data/spec/deprecate/evented_mailbox_spec.rb +0 -34
  169. data/spec/deprecate/future_spec.rb +0 -32
  170. data/spec/deprecate/internal_pool_spec.rb +0 -4
  171. data/spec/support/env.rb +0 -21
@@ -0,0 +1,81 @@
1
+ require "celluloid"
2
+
3
+ # !!! DO NOT INTRODUCE ADDITIONAL GLOBAL VARIABLES !!!
4
+ # rubocop:disable Style/GlobalVars
5
+ $CELLULOID_MONITORING = true
6
+ # rubocop:enable Style/GlobalVars
7
+
8
+ module Celluloid
9
+ class Probe
10
+ include Celluloid
11
+ include Celluloid::Notifications
12
+
13
+ NOTIFICATIONS_TOPIC_BASE = "celluloid.events.%s".freeze
14
+ EVENTS_BUFFER = Queue.new
15
+
16
+ class << self
17
+ def run
18
+ # spawn the actor if not found
19
+ supervise_as(:probe_actor) unless Actor[:probe_actor] && Actor[:probe_actor].alive?
20
+ end
21
+
22
+ def run_without_supervision
23
+ Actor[:probe_actor] = Celluloid::Probe.new
24
+ end
25
+
26
+ def actor_created(actor)
27
+ trigger_event(:actor_created, actor)
28
+ end
29
+
30
+ def actor_named(actor)
31
+ trigger_event(:actor_named, actor)
32
+ end
33
+
34
+ def actor_died(actor)
35
+ trigger_event(:actor_died, actor)
36
+ end
37
+
38
+ def actors_linked(a, b)
39
+ a = find_actor(a)
40
+ b = find_actor(b)
41
+ trigger_event(:actors_linked, a, b)
42
+ end
43
+
44
+ private
45
+
46
+ def trigger_event(name, *args)
47
+ # !!! DO NOT INTRODUCE ADDITIONAL GLOBAL VARIABLES !!!
48
+ # rubocop:disable Style/GlobalVars
49
+ return unless $CELLULOID_MONITORING
50
+ # rubocop:enable Style/GlobalVars
51
+
52
+ EVENTS_BUFFER << [name, args]
53
+ probe_actor = Actor[:probe_actor]
54
+ probe_actor.async.process_queue if probe_actor
55
+ end
56
+
57
+ def find_actor(obj)
58
+ if obj.__send__(:class) == Actor
59
+ obj
60
+ elsif owner = obj.instance_variable_get(OWNER_IVAR)
61
+ owner
62
+ end
63
+ end
64
+ end
65
+
66
+ def initialize
67
+ async.process_queue
68
+ end
69
+
70
+ def process_queue
71
+ until EVENTS_BUFFER.empty?
72
+ event = EVENTS_BUFFER.pop
73
+ dispatch_event(*event)
74
+ end
75
+ end
76
+
77
+ def dispatch_event(cmd, args)
78
+ publish(NOTIFICATIONS_TOPIC_BASE % cmd, args)
79
+ end
80
+ end
81
+ end
@@ -8,7 +8,7 @@ end
8
8
  # Base class of Celluloid proxies
9
9
  class Celluloid::Proxy::Abstract < BasicObject
10
10
  # Needed for storing proxies in data structures
11
- needed = [:object_id, :__id__, :hash, :eql?, :private_methods] - instance_methods
11
+ needed = %i[object_id __id__ hash eql? private_methods] - instance_methods
12
12
  if needed.any?
13
13
  include ::Kernel.dup.module_eval {
14
14
  undef_method(*(instance_methods - needed))
@@ -16,9 +16,9 @@ class Celluloid::Proxy::Abstract < BasicObject
16
16
  }
17
17
  # rubinius bug? These methods disappear when we include hacked kernel
18
18
  define_method :==, ::BasicObject.instance_method(:==) unless instance_methods.include?(:==)
19
- alias_method(:equal?, :==) unless instance_methods.include?(:equal?)
19
+ alias equal? == unless instance_methods.include?(:equal?)
20
20
  end
21
-
21
+
22
22
  def __class__
23
23
  @class ||= ::Celluloid::Proxy.class_of(self)
24
24
  end
@@ -26,25 +26,25 @@ end
26
26
 
27
27
  class Celluloid::Proxy::AbstractCall < Celluloid::Proxy::Abstract
28
28
  attr_reader :mailbox
29
-
29
+
30
30
  def initialize(mailbox, klass)
31
31
  @mailbox = mailbox
32
32
  @klass = klass
33
33
  end
34
-
34
+
35
35
  def eql?(other)
36
- self.__class__.eql?(::Celluloid::Proxy.class_of(other)) and @mailbox.eql?(other.mailbox)
36
+ __class__.eql?(::Celluloid::Proxy.class_of(other)) && @mailbox.eql?(other.mailbox)
37
37
  end
38
38
 
39
39
  def hash
40
40
  @mailbox.hash
41
41
  end
42
-
42
+
43
43
  def __klass__
44
44
  @klass
45
45
  end
46
-
46
+
47
47
  def inspect
48
- "#<#{self.__class__}(#{@klass})>"
48
+ "#<#{__class__}(#{@klass})>"
49
49
  end
50
50
  end
@@ -7,7 +7,7 @@ class Celluloid::Proxy::Async < Celluloid::Proxy::AbstractCall
7
7
  end
8
8
  if block_given?
9
9
  # FIXME: nicer exception
10
- fail "Cannot use blocks with async yet"
10
+ raise "Cannot use blocks with async yet"
11
11
  end
12
12
  @mailbox << ::Celluloid::Call::Async.new(meth, args, block)
13
13
  self
@@ -1,7 +1,7 @@
1
1
  class Celluloid::Proxy::Block
2
2
  attr_writer :execution
3
3
  attr_reader :call, :block
4
-
4
+
5
5
  def initialize(mailbox, call, block)
6
6
  @mailbox = mailbox
7
7
  @call = call
@@ -18,7 +18,7 @@ class Celluloid::Proxy::Block
18
18
  task.suspend(:invokeblock)
19
19
  else
20
20
  # FIXME: better exception
21
- fail "No task to suspend"
21
+ raise "No task to suspend"
22
22
  end
23
23
  end
24
24
  else
@@ -22,7 +22,7 @@ class Celluloid::Proxy::Cell < Celluloid::Proxy::Sync
22
22
  ::Celluloid::Internals::Method.new(self, name)
23
23
  end
24
24
 
25
- alias_method :sync, :method_missing
25
+ alias sync method_missing
26
26
 
27
27
  # Obtain an async proxy or explicitly invoke a named async method
28
28
  def async(method_name = nil, *args, &block)
@@ -1,13 +1,11 @@
1
1
  # A proxy which creates future calls to an actor
2
2
  class Celluloid::Proxy::Future < Celluloid::Proxy::AbstractCall
3
3
  def method_missing(meth, *args, &block)
4
- unless @mailbox.alive?
5
- fail ::Celluloid::DeadActorError, "attempted to call a dead actor: #{meth}"
6
- end
4
+ raise ::Celluloid::DeadActorError, "attempted to call a dead actor: #{meth}" unless @mailbox.alive?
7
5
 
8
6
  if block_given?
9
7
  # FIXME: nicer exception
10
- fail "Cannot use blocks with futures yet"
8
+ raise "Cannot use blocks with futures yet"
11
9
  end
12
10
 
13
11
  future = ::Celluloid::Future.new
@@ -5,9 +5,7 @@ class Celluloid::Proxy::Sync < Celluloid::Proxy::AbstractCall
5
5
  end
6
6
 
7
7
  def method_missing(meth, *args, &block)
8
- unless @mailbox.alive?
9
- fail ::Celluloid::DeadActorError, "attempted to call a dead actor: #{meth}"
10
- end
8
+ raise ::Celluloid::DeadActorError, "attempted to call a dead actor: #{meth}" unless @mailbox.alive?
11
9
 
12
10
  if @mailbox == ::Thread.current[:celluloid_mailbox]
13
11
  args.unshift meth
@@ -1,40 +1,26 @@
1
- require "dotenv"
2
- require "nenv"
3
-
4
1
  require "celluloid/test"
5
2
 
6
- # To help produce better bug reports in Rubinius
7
- if RUBY_ENGINE == "rbx"
8
- # $DEBUG = true # would be nice if this didn't fail ... :(
9
- require "rspec/matchers"
10
- require "rspec/matchers/built_in/be"
11
- end
12
-
13
- require "rspec/retry"
14
-
15
3
  module Specs
16
-
17
- CHECK_LOOSE_THREADS = !Nenv.ci? unless defined? CHECK_LOOSE_THREADS
4
+ CHECK_LOOSE_THREADS = false
18
5
  ALLOW_RETRIES = 3 unless defined? ALLOW_RETRIES
19
6
 
20
- INCLUDE_SUPPORT = [
21
- "env",
22
- "logging",
23
- "sleep_and_wait",
24
- "reset_class_variables",
25
- "crash_checking",
26
- "loose_threads",
27
- "stubbing",
28
- "coverage",
29
- "includer",
30
- "configure_rspec"
31
- ]
7
+ INCLUDE_SUPPORT = %w[
8
+ logging
9
+ sleep_and_wait
10
+ reset_class_variables
11
+ crash_checking
12
+ loose_threads
13
+ stubbing
14
+ coverage
15
+ includer
16
+ configure_rspec
17
+ ].freeze
32
18
 
33
19
  INCLUDE_PATHS = [
34
20
  "./spec/support/*.rb",
35
21
  "./spec/support/examples/*.rb",
36
22
  "./spec/shared/*.rb"
37
- ]
23
+ ].freeze
38
24
 
39
25
  MAX_EXECUTION = 13
40
26
  MAX_ATTEMPTS = 20
@@ -48,24 +34,27 @@ module Specs
48
34
  "rspec-retry",
49
35
  "rubysl-thread",
50
36
  "rubysl-timeout"
51
- ]
37
+ ].freeze
52
38
  end
53
39
 
40
+ # !!! DO NOT INTRODUCE ADDITIONAL GLOBAL VARIABLES !!!
41
+ # rubocop:disable Style/GlobalVars
54
42
  $CELLULOID_DEBUG = true
55
43
 
56
44
  # Require but disable, so it has to be explicitly enabled in tests
57
45
  require "celluloid/probe"
58
46
  $CELLULOID_MONITORING = false
47
+ # rubocop:enable Style/GlobalVars
59
48
 
60
49
  Celluloid.shutdown_timeout = 1
61
50
 
62
51
  # Load shared examples and test support code for other gems to use.
63
52
 
64
- Specs::INCLUDE_SUPPORT.each { |f|
65
- require "#{File.expand_path('../../../spec/support', __FILE__)}/#{f}.rb"
66
- }
53
+ Specs::INCLUDE_SUPPORT.each do |f|
54
+ require "#{File.expand_path('../../spec/support', __dir__)}/#{f}.rb"
55
+ end
67
56
 
68
57
  Specs.reset_probe(nil)
69
58
 
70
- Dir["#{File.expand_path('../../../spec/support/examples', __FILE__)}/*.rb"].map { |f| require f }
71
- Dir["#{File.expand_path('../../../spec/shared', __FILE__)}/*.rb"].map { |f| require f }
59
+ Dir["#{File.expand_path('../../spec/support/examples', __dir__)}/*.rb"].map { |f| require f }
60
+ Dir["#{File.expand_path('../../spec/shared', __dir__)}/*.rb"].map { |f| require f }
@@ -0,0 +1,8 @@
1
+ module Celluloid
2
+ module Supervision
3
+ class Configuration
4
+ class Injection
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,113 @@
1
+ module Celluloid
2
+ module Supervision
3
+ class Configuration
4
+ class Instance
5
+ attr_accessor :configuration
6
+
7
+ def initialize(configuration = {})
8
+ @state = :initializing # :ready
9
+ resync_accessors
10
+ @configuration = configuration
11
+ define(configuration) if configuration.any?
12
+ end
13
+
14
+ def export
15
+ @configuration.reject { |k, _v| REMOVE_AT_EXPORT.include? k }
16
+ end
17
+
18
+ def ready?(fail = false)
19
+ unless @state == :ready
20
+ @state = :ready if Configuration.valid? @configuration, fail
21
+ end
22
+ @state == :ready
23
+ end
24
+
25
+ def define(instance, fail = false)
26
+ raise Configuration::Error::AlreadyDefined if ready? fail
27
+ invoke_injection(:before_configuration)
28
+ @configuration = Configuration.options(instance)
29
+ ready?
30
+ end
31
+
32
+ def injection!(key, proc)
33
+ @configuration[:injections] ||= {}
34
+ @configuration[:injections][key] = proc
35
+ end
36
+
37
+ def injections!(_procs)
38
+ @configuration[:injections] = proces
39
+ end
40
+
41
+ def resync_accessors
42
+ # methods for setting and getting the usual defaults
43
+ Configuration.parameters(:mandatory, :optional, :plugins, :meta).each do |key|
44
+ self.class.instance_eval do
45
+ remove_method :"#{key}!" rescue nil # avoid warnings in tests
46
+ define_method(:"#{key}!") { |value| @configuration[key] = value }
47
+ end
48
+ self.class.instance_eval do
49
+ remove_method :"#{key}=" rescue nil # avoid warnings in tests
50
+ define_method(:"#{key}=") { |value| @configuration[key] = value }
51
+ end
52
+ self.class.instance_eval do
53
+ remove_method :"#{key}?" rescue nil # avoid warnings in tests
54
+ define_method(:"#{key}?") { !@configuration[key].nil? }
55
+ end
56
+ self.class.instance_eval do
57
+ remove_method :"#{key}" rescue nil # avoid warnings in tests
58
+ define_method(:"#{key}") { @configuration[key] }
59
+ end
60
+ end
61
+
62
+ Configuration.aliases.each do |_alias, _original|
63
+ ["!", :"=", :"?", :""]. each do |m|
64
+ self.class.instance_eval do
65
+ remove_method :"#{_alias}#{m}" rescue nil # avoid warnings in tests
66
+ alias_method :"#{_alias}#{m}", :"#{_original}#{m}"
67
+ end
68
+ end
69
+ end
70
+ true
71
+ end
72
+
73
+ def merge!(values)
74
+ @configuration = @configuration.merge(values)
75
+ end
76
+
77
+ def merge(values)
78
+ if values.is_a? Configuration
79
+ @configuration.merge(values.configuration)
80
+ elsif values.is_a? Hash
81
+ @configuration.merge(values)
82
+ else
83
+ raise Error::Invalid
84
+ end
85
+ end
86
+
87
+ def key?(k)
88
+ @configuration.key?(k)
89
+ end
90
+
91
+ def set(key, value)
92
+ @configuration[key] = value
93
+ end
94
+ alias []= set
95
+
96
+ def get(key)
97
+ @configuration[key]
98
+ end
99
+ alias [] get
100
+
101
+ def delete(k)
102
+ @configuration.delete(k)
103
+ end
104
+
105
+ private
106
+
107
+ def invoke_injection(_point)
108
+ # de puts "injection? #{point}"
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,169 @@
1
+ module Celluloid
2
+ module Supervision
3
+ class Configuration
4
+ class << self
5
+ def deploy(options = {})
6
+ define(options).deploy
7
+ end
8
+
9
+ def define(options = {})
10
+ new(options)
11
+ end
12
+ end
13
+
14
+ extend Forwardable
15
+
16
+ def_delegators :current_instance,
17
+ :delete,
18
+ :key?,
19
+ :set,
20
+ :get,
21
+ :[],
22
+ :[]=,
23
+ :injection!,
24
+ :injections!
25
+
26
+ attr_accessor :instances
27
+
28
+ def initialize(options = {})
29
+ @instances = [Instance.new]
30
+ @branch = :services
31
+ @i = 0 # incrementer of instances in this branch
32
+ resync_accessors
33
+ @configuration = options
34
+
35
+ if options.is_a? Hash
36
+ options[:configuration] ||= Container::Behavior.configure(options)
37
+ @configuration = instance_eval(&options[:configuration])
38
+ @supervisor ||= @configuration.fetch(:supervisor, :"Celluloid.services")
39
+ end
40
+ @supervisor ||= :"Celluloid.services"
41
+
42
+ define(@configuration) if (@configuration.is_a?(Hash) || @configuration.is_a?(Array)) && @configuration.any?
43
+ end
44
+
45
+ def provider
46
+ @provider ||= if @supervisor.is_a? Hash
47
+ @supervisor[:type].run!(@supervisor)
48
+ elsif @supervisor.is_a? Symbol
49
+ @supervisor = Object.module_eval(@supervisor.to_s)
50
+ provider
51
+ elsif @supervisor.is_a? Class
52
+ @supervisor.run!
53
+ elsif @supervisor.respond_to? :supervise
54
+ @supervisor
55
+ else
56
+ raise Error::InvalidSupervisor
57
+ end
58
+ end
59
+
60
+ def deploy(options = {})
61
+ define(options) if options.any?
62
+ @instances.each do |instance|
63
+ provider.add instance.merge(branch: @branch)
64
+ end
65
+ provider
66
+ end
67
+
68
+ def count
69
+ @instances.count
70
+ end
71
+
72
+ def each(&block)
73
+ @instances.each(&block)
74
+ end
75
+
76
+ def resync_accessors
77
+ # methods for setting and getting the usual defaults
78
+ Configuration.parameters(:mandatory, :optional, :plugins, :meta).each do |key|
79
+ [:"#{key}!", :"#{key}="].each do |m|
80
+ self.class.instance_eval do
81
+ remove_method :"#{m}" rescue nil # avoid warnings in tests
82
+ define_method(m) { |p| current_instance.send(m, p) }
83
+ end
84
+ end
85
+ [:"#{key}?", :"#{key}"].each do |m|
86
+ self.class.instance_eval do
87
+ remove_method :"#{m}" rescue nil # avoid warnings in tests
88
+ define_method(m) { current_instance.send(m) }
89
+ end
90
+ end
91
+ end
92
+
93
+ Configuration.aliases.each do |_alias, _original|
94
+ ["!", :"=", :"?", :""]. each do |m|
95
+ self.class.instance_eval do
96
+ remove_method :"#{_alias}#{m}" rescue nil # avoid warnings in tests
97
+ alias_method :"#{_alias}#{m}", :"#{_original}#{m}"
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def merge!(values)
104
+ if values.is_a?(Configuration) || values.is_a?(Hash)
105
+ current_instance.merge!(values)
106
+ else
107
+ raise Error::Invalid
108
+ end
109
+ end
110
+
111
+ def merge(values)
112
+ if values.is_a?(Configuration) || values.is_a?(Hash)
113
+ current_instance.merge(values)
114
+ else
115
+ raise Error::Invalid
116
+ end
117
+ end
118
+
119
+ def export
120
+ return current_instance.to_hash if @i == 0
121
+ @instances.map(&:export)
122
+ end
123
+
124
+ def include?(name)
125
+ @instances.map(&:name).include? name
126
+ end
127
+
128
+ def define(configuration, fail = false)
129
+ if configuration.is_a? Array
130
+ configuration.each { |c| define(c, fail) }
131
+ else
132
+ unless include? configuration[:as]
133
+ begin
134
+ current_instance.define(configuration, fail)
135
+ rescue Error::AlreadyDefined
136
+ increment
137
+ retry
138
+ end
139
+ end
140
+ end
141
+ self
142
+ end
143
+
144
+ def increment
145
+ @i += 1
146
+ end
147
+ alias another increment
148
+
149
+ def add(options)
150
+ define(options)
151
+ provider.supervise options if Configuration.valid? options
152
+ end
153
+
154
+ def shutdown
155
+ @provider.shutdown
156
+ end
157
+
158
+ private
159
+
160
+ def current_instance
161
+ @instances[@i] ||= Instance.new
162
+ end
163
+
164
+ def invoke_injection(_point)
165
+ # de puts "injection? #{point}"
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,123 @@
1
+ module Celluloid
2
+ module Supervision
3
+ # TODO: Do not hard-code. Allow configurable values.
4
+ INSTANCE_RETRY_WAIT = 3
5
+ INSTANCE_RETRY_LIMIT = 5
6
+
7
+ module Error
8
+ class NoPublicService < Celluloid::Error; end
9
+ end
10
+
11
+ class Configuration
12
+ module Error
13
+ class AlreadyDefined < Celluloid::Error; end
14
+ class InvalidSupervisor < Celluloid::Error; end
15
+ class InvalidValues < Celluloid::Error; end
16
+ class Incomplete < Celluloid::Error; end
17
+ class Invalid < Celluloid::Error; end
18
+ end
19
+
20
+ # Using class variable so that parameters can be added by plugins.
21
+
22
+ @@parameters = {
23
+
24
+ mandatory: [:type],
25
+
26
+ optional: %i[
27
+ as
28
+ args
29
+ block
30
+ ],
31
+
32
+ # TODO: Move these into Behaviors.
33
+ plugins: [
34
+ # de :size, # Supervision::Pool
35
+ # de :routers, # Supervision::Coordinator
36
+ # de :supervises # Supervision::Tree
37
+ ],
38
+
39
+ meta: %i[
40
+ registry
41
+ branch
42
+ method
43
+ ]
44
+ }
45
+
46
+ @@arity = {
47
+ type: :args
48
+ }
49
+
50
+ @@aliases = {
51
+ name: :as,
52
+ kind: :type,
53
+ # de :pool => :size, # TODO: Move into Behaviors.
54
+ # de :supervise => :supervises
55
+ }
56
+
57
+ @@defaults = {}
58
+
59
+ class << self
60
+ def save_defaults
61
+ @@defaults = {
62
+ parameters: @@parameters.each_with_object({}) { |(k, v), p| p[k] = v.dup; },
63
+ aliases: @@aliases.dup,
64
+ arity: @@arity.dup
65
+ }
66
+ end
67
+
68
+ def resync_parameters
69
+ @@parameters = @@defaults[:parameters].each_with_object({}) { |(k, v), p| p[k] = v.dup; }
70
+ @@aliases = @@defaults[:aliases].dup
71
+ @@arity = @@defaults[:arity].dup
72
+ end
73
+
74
+ def parameters(*args)
75
+ args.inject([]) { |parameters, p| parameters += @@parameters[p]; parameters }
76
+ end
77
+
78
+ def parameter!(key, value)
79
+ @@parameters[key] << value unless @@parameters[key].include? value
80
+ end
81
+
82
+ def arity
83
+ @@arity
84
+ end
85
+
86
+ def arity!(key, value)
87
+ @@arity[key] = value
88
+ end
89
+
90
+ def aliases
91
+ @@aliases
92
+ end
93
+
94
+ def alias!(aliased, original)
95
+ @@aliases[aliased] = original
96
+ end
97
+ end
98
+
99
+ save_defaults
100
+ resync_parameters
101
+
102
+ # This was originally added for `#pool` and `PoolManager
103
+ # `:before_initialize` was added to allow detecting `:size => N`
104
+ # and turning that into a pool. Other uses could be for `coordinator`
105
+ # appointing a `router` by detecting `:routers => N`, and many other uses.
106
+
107
+ ################ These are applied inside Supervision::Member ################
108
+
109
+ REMOVE_AT_EXPORT = %i[
110
+ configuration
111
+ behavior
112
+ ].freeze
113
+
114
+ INJECTIONS = %i[
115
+ configuration
116
+ before_initialization
117
+ after_initialization
118
+ before_start
119
+ before_restart
120
+ ].freeze
121
+ end
122
+ end
123
+ end