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'