1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
module Celluloid
# Supervise actor instances in a container.
module Supervision
class Container
include Celluloid
trap_exit :restart_actor
class << self
def define(options)
Configuration.define(top(options))
end
def deploy(options)
Configuration.deploy(top(options))
end
def top(options)
{
as: options.delete(:as),
type: (options.delete(:type) || self),
branch: (options.delete(:branch) || :services),
supervise: options.delete(:supervise) || []
}
end
# Actors or sub-applications to be supervised
def blocks
@blocks ||= []
end
# Start this application (and watch it with a supervisor)
def run!(options = {})
container = new(options) do |g|
blocks.each do |block|
block.call(g)
end
end
container
end
# Run the application in the foreground with a simple watchdog
def run(options = {})
loop do
supervisor = run!(options)
# Take five, toplevel supervisor
sleep 5 while supervisor.alive? # Why 5?
Internals::Logger.error "!!! Celluloid::Supervision::Container #{self} crashed. Restarting..."
end
end
end
finalizer :finalize
attr_accessor :registry
# Start the container.
def initialize(options = {})
options = { registry: options } if options.is_a? Internals::Registry
@state = :initializing
@actors = [] # instances in the container
@registry = options.delete(:registry) || Celluloid.actor_system.registry
@branch = options.delete(:branch) || :services
yield current_actor if block_given?
end
execute_block_on_receiver :initialize, :supervise, :supervise_as
def add(configuration)
Configuration.valid?(configuration, true)
@actors << Instance.new(configuration.merge(registry: @registry, branch: @branch))
@state = :running
add_accessors configuration
Actor.current
end
def add_accessors(configuration)
if configuration[:as]
unless methods.include? configuration[:as]
self.class.instance_eval do
define_method(configuration[:as]) do
@registry[configuration[:as]]
end
end
end
end
end
def remove_accessors; end
def remove(actor)
actor = Celluloid::Actor[actor] if actor.is_a? Symbol
instance = find(actor)
instance.terminate if instance
end
def actors
@actors.map(&:actor)
end
def find(actor)
@actors.find do |instance|
instance.actor == actor
end
end
def [](actor_name)
@registry[actor_name]
end
# Restart a crashed actor
def restart_actor(actor, reason)
return if @state == :shutdown
instance = find(actor)
raise "a container instance went missing. This shouldn't be!" unless instance
if reason
exclusive { instance.restart }
else
instance.cleanup
@actors.delete(instance)
end
end
def shutdown
@state = :shutdown
finalize
end
private
def finalize
if @actors
@actors.reverse_each do |instance|
instance.terminate
@actors.delete(instance)
end
end
end
end
end
end
|