lib/celluloid/supervision/container/instance.rb
module Celluloid
# Supervise collections of actors as a group
module Supervision
class Container
class Instance
attr_reader :name, :actor
# @option options [#call, Object] :args ([]) arguments array for the
# actor's constructor (lazy evaluation if it responds to #call)
def initialize(configuration = {})
@type = configuration.delete(:type)
@registry = configuration.delete(:registry)
@branch = configuration.delete(:branch) || :services
@configuration = configuration
# allows injections inside initialize, start, and restart
@injections = configuration.delete(:injections) || {}
invoke_injection(:before_initialize)
# Stringify keys :/
# de @configuration = configuration.each_with_object({}) { |(k,v), h| h[k.to_s] = v }
@name = @configuration[:as]
@block = @configuration[:block]
@args = prepare_args(@configuration[:args])
@method = @configuration[:method] || "new_link"
add_accessors
invoke_injection(:after_initialize)
start
end
def start
invoke_injection(:before_start)
@actor = @type.send(@method, *@args, &@block)
@registry.add(@name, @actor, @branch) if @name
invoke_injection(:after_start)
rescue Celluloid::TaskTimeout => ex
Internals::Logger.error("TaskTimeout at start of supervised instance of #{@type}")
raise ex
# TODO: Implement timeout/retry(?)
rescue => ex
Internals::Logger.error("Error ( #{ex.class} ) at start of supervised instance of #{@type}")
raise ex
end
def restart
# no need to reset @actor, as this is called in an `exclusive {}` block
# @actor = nil
# cleanup
invoke_injection(:before_restart)
start
invoke_injection(:after_restart)
end
def terminate
@actor.terminate if @actor
cleanup
rescue DeadActorError
end
def cleanup
@registry.delete(@name) if @name
end
private
def add_accessors
remove_accessors
if @configuration[:accessors].is_a? Array
# TODO: Decide which level to keep, and only keep that.
# Do we provide access by Celluloid.accessor
# Do we provide access by Celluloid.actor_system.accessor
@configuration[:accessors].each do |name|
Celluloid.instance_exec(@configuration[:as], name) do |actor, _where|
define_method(name) do
Celluloid.actor_system[actor]
end
end
Celluloid::Actor::System.instance_exec(@configuration[:as], name) do |actor, _where|
define_method(name) do
Celluloid.actor_system[actor]
end
end
end
end
end
def remove_accessors
if @configuration[:accessors].is_a? Array
@configuration[:accessors].each do |name|
Celluloid.instance_eval do
remove_method(name) rescue nil # avoid warnings in tests
end
Celluloid::Actor::System.instance_eval do
remove_method(name) rescue nil # avoid warnings in tests
end
end
end
end
def invoke_injection(name)
return unless @injections
block = @injections[name]
instance_eval(&block) if block.is_a? Proc
end
# Executes args if it has the method #call, and converts the return
# value to an Array. Otherwise, it just converts it to an Array.
def prepare_args(args)
args = args.call if args.respond_to?(:call)
Array(args)
end
end
end
end
end