lib/celluloid.rb in celluloid-0.8.0 vs lib/celluloid.rb in celluloid-0.9.0

- old
+ new

@@ -1,9 +1,11 @@ require 'logger' require 'thread' +require 'timeout' module Celluloid + SHUTDOWN_TIMEOUT = 60 # How long actors have to terminate @logger = Logger.new STDERR class << self attr_accessor :logger # Thread-safe logger class @@ -14,10 +16,15 @@ # Are we currently inside of an actor? def actor? !!Thread.current[:actor] end + # Is current actor running in exclusive mode? + def exclusive? + actor? and Thread.current[:actor].exclusive? + end + # Obtain the currently running actor (if one exists) def current_actor actor = Thread.current[:actor] raise NotActorError, "not in actor scope" unless actor actor.proxy @@ -41,18 +48,47 @@ actor.sleep(interval) else Kernel.sleep interval end end + + # Define an exception handler for actor crashes + def exception_handler(&block) + Logger.exception_handler(&block) + end + + # Shut down all running actors + # FIXME: This should probably attempt a graceful shutdown of the supervision + # tree before iterating through all actors and telling them to terminate. + def shutdown + Timeout.timeout(SHUTDOWN_TIMEOUT) do + futures = Actor.all.each do |actor| + begin + actor.future(:terminate) + rescue DeadActorError, MailboxError + end + end + + futures.each do |future| + begin + future.value + rescue DeadActorError, MailboxError + end + end + end + end end + # Terminate all actors at exit + at_exit { shutdown } + # Class methods added to classes which include Celluloid module ClassMethods # Create a new actor def new(*args, &block) proxy = Actor.new(allocate).proxy - proxy.send(:initialize, *args, &block) + proxy.send(:__send__, :initialize, *args, &block) proxy end alias_method :spawn, :new # Create a new actor and link to the current one @@ -60,11 +96,11 @@ current_actor = Celluloid.current_actor raise NotActorError, "can't link outside actor context" unless current_actor proxy = Actor.new(allocate).proxy current_actor.link proxy - proxy.send(:initialize, *args, &block) + proxy.send(:__send__, :initialize, *args, &block) proxy end alias_method :spawn_link, :new_link # Create a supervisor which ensures an instance of an actor will restart @@ -88,15 +124,30 @@ attr_reader :exit_handler # Configure a custom mailbox factory def use_mailbox(klass = nil, &block) if block - define_method(:mailbox_factory, &block) + @mailbox_factory = block else - define_method(:mailbox_factory) { klass.new } + @mailbox_factory = proc { klass.new } end end + + # Create a mailbox for this actor + def mailbox_factory + if defined?(@mailbox_factory) + @mailbox_factory.call + elsif defined?(super) + super + else + Mailbox.new + end + end + + def ===(other) + other.kind_of? self + end end # # Instance methods # @@ -191,11 +242,17 @@ # Sleep while letting the actor continue to receive messages def sleep(interval) Celluloid.sleep(interval) end - # Call a block after a given interval + # Run given block in an exclusive mode: all synchronous calls block the whole + # actor, not only current message processing. + def exclusive(&block) + Thread.current[:actor].exclusive(&block) + end + + # Call a block after a given interval, returning a Celluloid::Timer object def after(interval, &block) Thread.current[:actor].after(interval, &block) end # Perform a blocking or computationally intensive action inside an @@ -205,15 +262,10 @@ # This implementation relies on the present implementation of # Celluloid::Future, which uses an Actor to run the block Future.new(&block).value end - # Deprecated, do not use - def async - raise "Celluloid#async is defunct. Please use #defer instead" - end - # Process async calls via method_missing def method_missing(meth, *args, &block) # bang methods are async calls if meth.to_s.match(/!$/) unbanged_meth = meth.to_s.sub(/!$/, '') @@ -243,9 +295,10 @@ require 'celluloid/fiber' require 'celluloid/fsm' require 'celluloid/links' require 'celluloid/logger' require 'celluloid/mailbox' +require 'celluloid/pool' require 'celluloid/receivers' require 'celluloid/registry' require 'celluloid/responses' require 'celluloid/signals' require 'celluloid/task'