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.
- checksums.yaml +4 -4
- data/CHANGES.md +300 -81
- data/CONDUCT.md +13 -0
- data/CONTRIBUTING.md +39 -0
- data/README.md +54 -155
- data/REFACTOR.md +1 -0
- data/architecture.md +120 -0
- data/examples/basic_usage.rb +1 -1
- data/examples/configurations.rb +78 -0
- data/examples/futures.rb +1 -1
- data/examples/ring.rb +5 -4
- data/examples/simple_pmap.rb +1 -1
- data/examples/stack.rb +2 -2
- data/examples/supervisors_and_registry.rb +82 -0
- data/examples/timers.rb +2 -2
- data/lib/celluloid/actor/system.rb +13 -29
- data/lib/celluloid/actor.rb +27 -17
- data/lib/celluloid/autostart.rb +6 -1
- data/lib/celluloid/call/async.rb +2 -0
- data/lib/celluloid/call/sync.rb +10 -3
- data/lib/celluloid/calls.rb +13 -12
- data/lib/celluloid/cell.rb +5 -9
- data/lib/celluloid/condition.rb +3 -3
- data/lib/celluloid/core_ext.rb +0 -2
- data/lib/celluloid/debug.rb +3 -0
- data/lib/celluloid/exceptions.rb +2 -2
- data/lib/celluloid/future.rb +8 -10
- data/lib/celluloid/group/pool.rb +1 -3
- data/lib/celluloid/group/spawner.rb +2 -6
- data/lib/celluloid/group.rb +12 -8
- data/lib/celluloid/internals/call_chain.rb +15 -0
- data/lib/celluloid/internals/cpu_counter.rb +62 -0
- data/lib/celluloid/internals/handlers.rb +42 -0
- data/lib/celluloid/internals/links.rb +38 -0
- data/lib/celluloid/internals/logger.rb +104 -0
- data/lib/celluloid/internals/method.rb +34 -0
- data/lib/celluloid/internals/properties.rb +32 -0
- data/lib/celluloid/internals/receivers.rb +64 -0
- data/lib/celluloid/internals/registry.rb +102 -0
- data/lib/celluloid/internals/responses.rb +46 -0
- data/lib/celluloid/internals/signals.rb +24 -0
- data/lib/celluloid/internals/stack/dump.rb +12 -0
- data/lib/celluloid/internals/stack/states.rb +72 -0
- data/lib/celluloid/internals/stack/summary.rb +12 -0
- data/lib/celluloid/internals/stack.rb +74 -0
- data/lib/celluloid/internals/task_set.rb +51 -0
- data/lib/celluloid/internals/thread_handle.rb +52 -0
- data/lib/celluloid/internals/uuid.rb +40 -0
- data/lib/celluloid/logging/incident.rb +21 -0
- data/lib/celluloid/logging/incident_logger.rb +147 -0
- data/lib/celluloid/logging/incident_reporter.rb +49 -0
- data/lib/celluloid/logging/log_event.rb +20 -0
- data/lib/celluloid/logging/ring_buffer.rb +64 -0
- data/lib/celluloid/mailbox/evented.rb +13 -5
- data/lib/celluloid/mailbox.rb +22 -9
- data/lib/celluloid/notifications.rb +95 -0
- data/lib/celluloid/pool.rb +6 -0
- data/lib/celluloid/probe.rb +81 -0
- data/lib/celluloid/proxy/abstract.rb +9 -9
- data/lib/celluloid/proxy/async.rb +1 -1
- data/lib/celluloid/proxy/block.rb +2 -2
- data/lib/celluloid/proxy/cell.rb +1 -1
- data/lib/celluloid/proxy/future.rb +2 -4
- data/lib/celluloid/proxy/sync.rb +1 -3
- data/lib/celluloid/rspec.rb +22 -33
- data/lib/celluloid/supervision/configuration/injections.rb +8 -0
- data/lib/celluloid/supervision/configuration/instance.rb +113 -0
- data/lib/celluloid/supervision/configuration.rb +169 -0
- data/lib/celluloid/supervision/constants.rb +123 -0
- data/lib/celluloid/supervision/container/behavior/pool.rb +71 -0
- data/lib/celluloid/supervision/container/behavior/tree.rb +23 -0
- data/lib/celluloid/supervision/container/behavior.rb +89 -0
- data/lib/celluloid/supervision/container/injections.rb +8 -0
- data/lib/celluloid/supervision/container/instance.rb +116 -0
- data/lib/celluloid/supervision/container/pool.rb +210 -0
- data/lib/celluloid/supervision/container.rb +144 -0
- data/lib/celluloid/supervision/service.rb +27 -0
- data/lib/celluloid/supervision/supervise.rb +34 -0
- data/lib/celluloid/supervision/validation.rb +40 -0
- data/lib/celluloid/supervision/version.rb +5 -0
- data/lib/celluloid/supervision.rb +17 -0
- data/lib/celluloid/system_events.rb +11 -6
- data/lib/celluloid/task/fibered.rb +6 -2
- data/lib/celluloid/task/threaded.rb +3 -3
- data/lib/celluloid/task.rb +25 -12
- data/lib/celluloid/test.rb +5 -2
- data/lib/celluloid/thread.rb +0 -2
- data/lib/celluloid/version.rb +1 -1
- data/lib/celluloid.rb +74 -64
- data/spec/celluloid/block_spec.rb +29 -32
- data/spec/celluloid/calls_spec.rb +5 -15
- data/spec/celluloid/future_spec.rb +7 -1
- data/spec/celluloid/internals/cpu_counter_spec.rb +129 -0
- data/spec/celluloid/internals/links_spec.rb +43 -0
- data/spec/celluloid/internals/properties_spec.rb +40 -0
- data/spec/celluloid/internals/registry_spec.rb +62 -0
- data/spec/celluloid/internals/stack/dump_spec.rb +4 -0
- data/spec/celluloid/internals/stack/summary_spec.rb +4 -0
- data/spec/celluloid/internals/thread_handle_spec.rb +60 -0
- data/spec/celluloid/internals/uuid_spec.rb +9 -0
- data/spec/celluloid/logging/ring_buffer_spec.rb +36 -0
- data/spec/celluloid/mailbox/evented_spec.rb +11 -22
- data/spec/celluloid/misc/leak_spec.rb +3 -4
- data/spec/celluloid/notifications_spec.rb +140 -0
- data/spec/celluloid/probe_spec.rb +102 -0
- data/spec/celluloid/proxy_spec.rb +30 -30
- data/spec/celluloid/supervision/behavior_spec.rb +74 -0
- data/spec/celluloid/supervision/configuration_spec.rb +181 -0
- data/spec/celluloid/supervision/container_spec.rb +72 -0
- data/spec/celluloid/supervision/instance_spec.rb +13 -0
- data/spec/celluloid/supervision/root_spec.rb +28 -0
- data/spec/celluloid/supervision/supervisor_spec.rb +93 -0
- data/spec/celluloid/task/fibered_spec.rb +1 -3
- data/spec/celluloid/task/threaded_spec.rb +1 -3
- data/spec/shared/actor_examples.rb +58 -33
- data/spec/shared/group_examples.rb +2 -2
- data/spec/shared/mailbox_examples.rb +1 -1
- data/spec/shared/stack_examples.rb +87 -0
- data/spec/shared/task_examples.rb +2 -3
- data/spec/spec_helper.rb +2 -4
- data/spec/support/configure_rspec.rb +2 -3
- data/spec/support/coverage.rb +2 -4
- data/spec/support/crash_checking.rb +2 -2
- data/spec/support/examples/actor_class.rb +3 -8
- data/spec/support/examples/call_class.rb +2 -2
- data/spec/support/examples/container_class.rb +35 -0
- data/spec/support/examples/evented_mailbox_class.rb +1 -2
- data/spec/support/examples/stack_classes.rb +58 -0
- data/spec/support/examples/stack_methods.rb +23 -0
- data/spec/support/examples/subordinate_class.rb +19 -0
- data/spec/support/logging.rb +3 -34
- data/spec/support/loose_threads.rb +3 -16
- data/spec/support/reset_class_variables.rb +5 -1
- data/spec/support/stubbing.rb +1 -1
- metadata +91 -289
- data/culture/CONDUCT.md +0 -28
- data/culture/Gemfile +0 -9
- data/culture/LICENSE.txt +0 -22
- data/culture/README.md +0 -22
- data/culture/Rakefile +0 -5
- data/culture/SYNC.md +0 -70
- data/culture/celluloid-culture.gemspec +0 -18
- data/culture/gems/README.md +0 -39
- data/culture/gems/dependencies.yml +0 -85
- data/culture/gems/loader.rb +0 -101
- data/culture/rubocop/README.md +0 -38
- data/culture/rubocop/lint.yml +0 -8
- data/culture/rubocop/metrics.yml +0 -15
- data/culture/rubocop/perf.yml +0 -0
- data/culture/rubocop/rubocop.yml +0 -5
- data/culture/rubocop/style.yml +0 -57
- data/culture/spec/gems_spec.rb +0 -2
- data/culture/spec/spec_helper.rb +0 -0
- data/culture/spec/sync_spec.rb +0 -2
- data/culture/sync.rb +0 -56
- data/culture/tasks/rspec.rake +0 -5
- data/culture/tasks/rubocop.rake +0 -2
- data/lib/celluloid/actor/manager.rb +0 -7
- data/lib/celluloid/backported.rb +0 -2
- data/lib/celluloid/current.rb +0 -2
- data/lib/celluloid/deprecate.rb +0 -21
- data/lib/celluloid/fiber.rb +0 -32
- data/lib/celluloid/managed.rb +0 -3
- data/lib/celluloid/notices.rb +0 -15
- data/spec/deprecate/actor_system_spec.rb +0 -72
- data/spec/deprecate/block_spec.rb +0 -52
- data/spec/deprecate/calls_spec.rb +0 -39
- data/spec/deprecate/evented_mailbox_spec.rb +0 -34
- data/spec/deprecate/future_spec.rb +0 -32
- data/spec/deprecate/internal_pool_spec.rb +0 -4
- 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 = [
|
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
|
-
|
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
|
-
|
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
|
-
"#<#{
|
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
|
-
|
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
|
-
|
21
|
+
raise "No task to suspend"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
else
|
data/lib/celluloid/proxy/cell.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
8
|
+
raise "Cannot use blocks with futures yet"
|
11
9
|
end
|
12
10
|
|
13
11
|
future = ::Celluloid::Future.new
|
data/lib/celluloid/proxy/sync.rb
CHANGED
@@ -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
|
data/lib/celluloid/rspec.rb
CHANGED
@@ -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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
65
|
-
require "#{File.expand_path('
|
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('
|
71
|
-
Dir["#{File.expand_path('
|
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,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
|