Git Product home page Git Product logo

celluloid's Introduction

Celluloid

Gem Version MIT licensed Build Status Maintained: no Gitter Chat

Celluloid is a framework for building asynchronous and multithreaded Ruby programs using object-oriented concepts.

Revival Process Underway

Celluloid is in the process of being refactored and released back into the wild during Google Summer of Code. The next era will not have one individual active maintainer, but a team of collaborators. Going forward, previously dormant maintainer Donovan Keme is returning to support future primary maintainer Emese Padányi during GSoC 2020. Her plan extends past the Summer program, and aims to revive the community and codebase of Celluloid together. Backing this process are Harsh Deep and GSoC alumni Dilum Navanjana. We welcome your collaboration and contributions in this massive work.

The codebase is being refactored to pursue a stable release with no deprecation warnings, and with this cleaned up:

Diagram

Diagram meticulously developed by Emese Padányi

Proudly supported by the best cloud infrastructure provider in the world: DigitalOcean

Discussion

Documentation

Please see the Celluloid Wiki for more detailed documentation and usage notes.

The following API documentation is also available:

Related Projects

See also: Projects Using Celluloid

  • Reel: An "evented" web server based on Celluloid::IO
  • DCell: The Celluloid actor protocol distributed over 0MQ
  • ECell: Mesh strategies for Celluloid actors distributed over 0MQ
  • Celluloid::IO: "Evented" IO support for Celluloid actors
  • Celluloid::ZMQ: "Evented" 0MQ support for Celluloid actors
  • Celluloid::DNS: An "evented" DNS server based on Celluloid::IO
  • Celluloid::SMTP: An "evented" SMTP server based on Celluloid::IO
  • nio4r: "New IO for Ruby": high performance IO selectors
  • Timers: A generic Ruby timer library for event-based systems

Contributing to Celluloid

  • Fork this repository on github
  • Make your changes and send us a pull request
  • Pull requests will be reviewed for inclusion in the project

License

Copyright (c) 2011-2018 Tony Arcieri, Donovan Keme.

Distributed under the MIT License. See LICENSE.txt for further details.

celluloid's People

Contributors

benlangfeld avatar benlovell avatar bsingr avatar cheald avatar chuckremes avatar cpuguy83 avatar digitalextremist avatar dilumn avatar e2 avatar emesepadanyi avatar grantr avatar halorgium avatar ioquatix avatar jc00ke avatar jeremyvdw avatar jnicklas avatar justincampbell avatar justinko avatar justinlove avatar marshall-lee avatar niamster avatar olleolleolle avatar p avatar p-vinayak avatar paddor avatar perlun avatar sb8244 avatar schmurfy avatar slyphon avatar tarcieri avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

celluloid's Issues

Shutdown actors gracefully at exit

Right now Celluloid has the Ruby VM go on an actor killing spree at shutdown. However, actors may want to take action at shutdown, such as persisting some state or informing remote actors they're shutting down in a DCell system.

Celluloid should use an at_exit handler to shut down all running actors gracefully. This can be overridden with exit! for a fast exit.

(Originally from: https://github.com/tarcieri/dcell/issues/2)

Can't call bang method on self

I was trying to async another method on the current actor using self:

def process
  something!
end

def something
  puts 'takes a long time'
end

Got a NoSuchMethod for something! Document the use of current_actor for these cases?

Prevent mailbox overflow

Hi,
What I want to implement is I have one actor which will read lines from a big file and dispatch those lines to a pool of workers for handling, I already found nearly all the pieces to do this but my problem is what is the preferred way to "pause" the dispatching when each actor's mailbox are full ?

Here is a test file for this:

require 'celluloid'

$stdout.sync = true

class Output
  include Celluloid

  def puts(msg)
    Kernel.puts(msg)
  end
end

class Worker
  include Celluloid

  def do(n)
    Actor[:stdout].puts! "[#{n}] started"
    Kernel::sleep(1)
    Actor[:stdout].puts! "[#{n}] done."
  end

end


Celluloid::Actor[:stdout] = Output.new

w = Worker.pool(size: 2)

1_000.times do |n|
  w.do!(n)
  # I would like to block here until workers are ready to accept more messages
end

sleep

When doing it like this each of the 1000 messages will be dispatched into a queue without consideration about the actor state, in my real project the message would fill up the available memory for nothing, I am sure I can come up with a system to limit how many messages will be queued with messages between the master and the workers in the pool but I am curious on how it could be done and if something can already handle it inside celluloid.

By looking at the pool class it looks like it already does some part of the work by only sending work to idle workers but do not limit how many messages can be waiting in its mailbox, my first impression is that by subclassing/extending it I could do what I want but I am not sure if this is the right approach.

Feature request: celluloid queue.

There is a need to call actor methods exactly one by one (like queue,
because the methods doing something with state of the actor, and should not be crossed).
Calls of the methods can happens asynchronously by some events.

Example actor:

class A
  include Celluloid

  def test(x)
    puts "test start #{x}"
    sleep 1
    puts "test end #{x} - #{Time.now}"
  end
end

a = A.new
a.test!(1)
a.test!(2)

sleep 3

The output is:

test start 1
test start 2
test end 1 - 2012-10-08 01:33:53 +0400
test end 2 - 2012-10-08 01:33:53 +0400

Not that needed.

I, also, can do this with futures:

class B
    include Celluloid

    def test(x, future = nil)
      future.value if future
      puts "test start #{x}"
      sleep 1
      puts "test end #{x} - #{Time.now}"
    end
end

b = B.new
f = b.future.test(1)
b.future.test(2, f)

sleep 3

The output is:

test start 1
test end 1 - 2012-10-08 01:39:10 +0400
test start 2
test end 2 - 2012-10-08 01:39:11 +0400

Ok, but this is ugly, change the methods logic, and actor can have more methods.

I, also, try it with pool.

pool = A.pool(size: 1)
pool.test!(1)
pool.test!(2)

sleep 3

This is not work, minimal of the pool size is 2.

So, the feature is:

queue = A.queue(:queue1)
queue.test!(1)
queue.test!(2)

Or

a.queue.test!(1)
a.queue.test!(2)

or

a.queue[:queue1].test!(1)
a.queue[:queue1].test!(2)

and output will be:

test start 1
test end 1 - 2012-10-08 01:39:10 +0400
test start 2
test end 2 - 2012-10-08 01:39:11 +0400

Or, perhaps, there is a similar functionality, but I have not found the documentation.

Memory leaks in links

Hello!

Basic case:

require 'celluloid'

class Foo
  include Celluloid
  def exc
    raise 'ololo'
  end
end

s = Foo.supervise

100.times do
  s.actors.first.exc!
  sleep 0.01
end

And as a result:

> s.links.count
 => 101

Leaky Pools

I find myself using the pool frequently, but i can't seem to find a way for it to not leak all its actors.

require 'celluloid'
class TestActor
  include Celluloid

  def do_stuff
    my_pool = TestActor.pool(:size => 10)
    my_futures = 10.times.map do |i|
      my_pool.future(:do_a_thing, i)
    end
    @answer = 0
    my_futures.each do |f|
      v = f.value
      @answer += v
    end
    my_pool.terminate
    say_the_answer
    puts "Actor Count: #{Celluloid::Actor.all.length} Alive: #{Celluloid::Actor.all.select(&:alive?).length}"
    #puts "Actors:#{Celluloid::Actor.all}"
    self.terminate
  end

  def say_the_answer
    puts "the answer is #{@answer}"
    `say the answer is #{@answer}`
  end

  def do_a_thing(num)
    voices = %w(Agnes Albert Alex Bad\ News Bahh Bells Boing Bruce Bubbles Cellos Deranged Fred Good\ News Hysterical Junior Kathy Pipe\ Organ Princess Ralph Trinoids Vicki Victoria Whisper Zarvox)
    voice = voices.sample
    `say --voice #{voice} I am number #{num}`
    return num
  end
end

(sorry for the mac only example)

When running TestActor.new.do_stuff multiple times, I get these actor counts:
Actor Count: 33 Alive: 28
Actor Count: 43 Alive: 38
Actor Count: 53 Alive: 48

I'm not sure why I have 28 live actors after the first run and subsequently it increases by 10. It seems like after first run I should have fanout, current TestActor, and maybe pool_size + pool_manager if they aren't terminating. Looks like the pool manager is terminating itself, just not the actors it is managing, but I'm not sure where 28 would come from.

Feature request: recurring timers

Pinging @benlangfeld by request.

I was looking at the docs for Celluloid Timers but I want a timer that happens continually. Example:

class TimerExample
  include Celluloid
  attr_reader :timer

  def initialize
    @timer = every(3) { puts "Timer fired!" }
  end
end

Would print "Timer fired!" every 3 seconds. Right now, I think I can use #after and just continually reschedule the code, but it'd be nicer if I could just request a continuous timer.

Sometimes actor crashes for no apparent reason

Hello,

I am brand new to ruby and celluloid

I have an error with celluloid ; Please see below snipplet:

My error results from the value assigned to runners

  1. For runners < 1000 all is well
  2. For runners 2000-5000 I sometimes get

Celluloid:DeadActorError: attempted to call a dead actor

  1. For runners >10000

FibreError: dead fiber called
Error: unable to create new native thread

The error that intrigues me more is error 2, why should the actor die ? Have I hit the limits ?

Error 3, I suspect I cant do much about possibly a java thing.

Please advise !

require 'celluloid'

runners=100000

class Rema
include Celluloid

def initialize
    @num = 0
end

def fix
    @num +=1
end

def values
    puts " got #{@num}"
end

end

hex = Rema.new

thing=[]

0.upto(runners){ |x|

q= Thread.new {
hex.fix!
}

thing << q

}
thing.each { |x| x.join}

hex.values

Debugging "stack level too deep" errors

Hi,

There is a bit of history to this on sidekiq/sidekiq#233. I am running Sidekiq on Heroku and see intermittent "stack level too deep" errors, causing my worker to die every now and then. I tried to debug this issue, but am not really able to identify the core problem. Here is what happens:

require 'sidekiq/cli'
options = Sidekiq.options.merge :concurrency => 1, :environment => Rails.env, :queues => ["default"]
Sidekiq::Manager.new(options).start!
# => Sidekiq::Manager crashed!
#    SystemStackError: stack level too deep
#    /app/vendor/bundle/ruby/1.9.1/gems/celluloid-0.11.0/lib/celluloid/task.rb:57
#    Sidekiq::Processor crashed!
#    SystemStackError: stack level too deep
#    /app/vendor/bundle/ruby/1.9.1/gems/celluloid-0.11.0/lib/celluloid/task.rb:57

I doubt that this has anything to do with my worker code, as the worker is not ever started. It seems to fail either right from the start or right before the next loop cycle.

Unfortunately, there is only a single backtrace line, which makes debugging seriously difficult. If I only could get a little more info. Could you point me into the right direction?

Thanks,
Dim

#exclusive and new_link are incompatible

Something like this raises Celluloid::TerminationRequest

class Foo
  include Celluloid

  def do
    exclusive { self.class.new_link }
  end
end
Foo.new.do

new_link has the new actor link itself back, not the other way round, and this deadlocks due to exclusive.

ThreadError when shutting down actors

Where adhearsion/core/spec/spec_helper.rb:48 is:

Celluloid.shutdown

I get a nasty mutex unlocking ThreadError:

  1) Adhearsion::PunchblockPlugin::Initializer#connect_to_server should not attempt to reconnect if Adhearsion is shutting down
     Failure/Error: Unable to find matching line from backtrace
     ThreadError:
       Attempt to unlock a mutex which is locked by another thread
     # /Users/ben/code/VoIP/adhearsion/core/vendor/ruby/1.9.1/gems/celluloid-0.9.1/lib/celluloid/mailbox.rb:74:in `unlock'
     # /Users/ben/code/VoIP/adhearsion/core/vendor/ruby/1.9.1/gems/celluloid-0.9.1/lib/celluloid/mailbox.rb:74:in `ensure in receive'
     # /Users/ben/code/VoIP/adhearsion/core/vendor/ruby/1.9.1/gems/celluloid-0.9.1/lib/celluloid/mailbox.rb:74:in `receive'
     # /Users/ben/code/VoIP/adhearsion/core/vendor/ruby/1.9.1/gems/celluloid-0.9.1/lib/celluloid/actor.rb:41:in `call'
     # /Users/ben/code/VoIP/adhearsion/core/vendor/ruby/1.9.1/gems/celluloid-0.9.1/lib/celluloid/actor_proxy.rb:80:in `method_missing'
     # /Users/ben/code/VoIP/adhearsion/core/vendor/ruby/1.9.1/gems/celluloid-0.9.1/lib/celluloid.rb:89:in `block (2 levels) in shutdown'
     # /Users/ben/code/VoIP/adhearsion/core/vendor/ruby/1.9.1/gems/celluloid-0.9.1/lib/celluloid.rb:87:in `each'
     # /Users/ben/code/VoIP/adhearsion/core/vendor/ruby/1.9.1/gems/celluloid-0.9.1/lib/celluloid.rb:87:in `block in shutdown'
     # /Users/ben/Developer/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/timeout.rb:68:in `timeout'
     # /Users/ben/code/VoIP/adhearsion/core/vendor/ruby/1.9.1/gems/celluloid-0.9.1/lib/celluloid.rb:75:in `shutdown'
     # /Users/ben/code/VoIP/adhearsion/core/spec/spec_helper.rb:48:in `block (2 levels) in <top (required)>'

Stubbing actor internals doesn't work

require 'celluloid'

class A
  include Celluloid

  def b
    c
  end

  def c
    "Hello"
  end
end

describe A do
  it "should allow mocking" do
    subject.should_receive(:c).twice.and_return "World"
    subject.c.should == "World"
    subject.b.should == "World"
  end
end

In this instance, it can be seen that from outside of the A instance, calling the stubbed method works, but it does not internally. Removing the Celluloid include causes the test to pass.

Any ideas?

stack dumper should build an object

If there was an object to hold all the stack dump data (Celluloid::StackDump.new perhaps) then the Incident class could hold a reference to it and it could be used in incident reports.

Actors via processes+IPC

Hey guys,

I already mentioned this idea to Tony... but I wanted to put it out there to see if others find it interesting.

Currently all actor libraries are built for GIL-free VM's.. such as JRuby or Rubinius' hydra branch. For developers still using MRI (1.9), you are out of luck. I've talked to some smart developers in the Ruby community and the general consensus is that MRI will never get rid of the GIL.. but might one day have MVM support. That is fine, but that shouldn't stop MRI from having the ability to take advantage of the actor concurrency model. It's just requires a different implementation built on processes+pipes+sockets.

Currently on JRuby/Rubinius, actors will spawn as native threads .. the OS will then schedule them across multiple cores, and those actors will share state by sending messages (method calls with mutexes). Now, my suggestion is to build the exact same celluloid API, but spawn`ing will fork a new process and setup a bi-directional pipe to pass state. Potentially, application developers could target JRuby, Rubinius or MRI with Celluoid and specify to use threads or processes.

Of course there are some implications.. forking is slow and expensive (copies the entire parent process). But there are always ways to make this better -- for example, we could be smart about what we fork, and make a master process that is very light and used to spawn actors. Besides, spawning a crap load of native threads won't be too fast either. Could run some benchmarks.

Any interest? My biggest concern here is bloating the celluloid code base... it will take some thought on how to architect this so the API's can be the same and the implementations are separated well. We could even get as crazy as having remote actors spawn on different systems. What I like about the actor model is its a clear interface for message-passing concurrency... any code can code to the interface, and use it in various ways. I think of it as what an ORM did for writing data models... but this time it's a concurrency abstraction.

Peter

Hang while testing Actor on 1.9.3

Clone mperham/sidekiq and run rake, the tests should run green. Now remove the conditional on lib/sidekiq/processor.rb line 7 and run rake again. It should hang. The associated test is in test/test_processor.rb

Actor#method returns a non-safe Method

When you call actor.method(:name), you get a Method handle to the wrapped object instead of the ActorProxy. If you later call this method it will be a direct call, not routed through the actor.

A use-case for this would be, for example, passing methods of an actor as a callback to some other method.

open('http://…', &actor.method(:handle_response))

A proposed solution (like we discussed in IRC) would be to implement ActorProxy#method, which would return a somewhat compatible object with Method. The reason for not returning an actual Method is that this fake Method could later on be serialized in DCell.

Creating a pool yields a stack level to deep error with MRI 1.9.3-p286

Hi!

I get a stack too deep exception when creating a pool:

$ irb
1.9.3-p286 :001 > require 'celluloid'
 => true 
1.9.3-p286 :002 > class Worker
1.9.3-p286 :003?>   include Celluloid
1.9.3-p286 :004?>   def foobar
1.9.3-p286 :005?>     "baz"
1.9.3-p286 :006?>     end
1.9.3-p286 :007?>   end
 => nil 
1.9.3-p286 :008 > Worker.pool
E, [2012-10-19T00:18:23.422135 #9773] ERROR -- : Celluloid::PoolManager crashed!
SystemStackError: stack level too deep
/home/oz/.rvm/rubies/ruby-1.9.3-p286/lib/ruby/1.9.1/irb/workspace.rb:80
SystemStackErrorE, [2012-10-19T00:18:23.422385 #9773] ERROR -- : Celluloid::PoolManager#finalize crashed!
NoMethodError: undefined method `+' for nil:NilClass
/home/oz/.rvm/gems/ruby-1.9.3-p286/gems/celluloid-0.12.2/lib/celluloid/pool_manager.rb:26:in `finalize'
/home/oz/.rvm/gems/ruby-1.9.3-p286/gems/celluloid-0.12.2/lib/celluloid/actor.rb:376:in `block in run_finalizer'
/home/oz/.rvm/gems/ruby-1.9.3-p286/gems/celluloid-0.12.2/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'
: stack level too deep
    from /home/oz/.rvm/gems/ruby-1.9.3-p286/gems/celluloid-0.12.2/lib/celluloid/actor.rb:207
1.9.3-p286 :009 > 

The host is Debian box (64bit):

$ uname -m 
x86_64
$ ruby -v
ruby 1.9.3p286 (2012-10-12 revision 37165) [x86_64-linux]

This may be linked to how rvm compiled this MRI, although I don't really see why. This code runs fine with JRuby 1.7.0.RC2 BTW. :)

Supervisor and registry example produces error

*** Demonstrating using the Supervisor API directly
I, [2012-09-13T09:42:59.491620 #5067] INFO -- : Terminating 4 actors...
I, [2012-09-13T09:42:59.492971 #5067] INFO -- : Shutdown completed cleanly
/home/hristo/Public/celluloid/lib/celluloid/calls.rb:12:in check_signature': undefined methodactor' for #Celluloid::SupervisionGroup:0x00000001602588 (NoMethodError)
from /home/hristo/Public/celluloid/lib/celluloid/calls.rb:50:in dispatch' from /home/hristo/Public/celluloid/lib/celluloid/actor.rb:320:inblock in handle_message'
from /home/hristo/Public/celluloid/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'

Release 0.6.0

Hi Toni,

There's a couple of changes since 0.5.0 that would be really nice to have released, including JRuby fixes and the #wrapped_object feature. Is there any chance a new release could be pushed out soon, incorporating these changes?

Running default actors (i.e. notification fanout) breaks shutdown in Resque

This one's a bastard. Sorry about that. :-) I am developing an application that uses Rails, Adhearsion, and Resque. I noticed a little while ago that the Resque workers weren't shutting down. You're supposed to issue a QUIT signal to the worker's PID and it then shuts down. The problem only occurs when the worker in started is BACKGROUND mode, which calls Ruby 1.9's Process.daemon behind the scenes. With some difficulty, I tracked the problem down to Celluloid. With 0.11.0, it worked, With 0.11.1, it didn't. 0.12.2 doesn't work either. I tracked the problem further using git bisect to 5affff6. It's a likely culprit but I don't understand Celluloid anywhere near well enough to try and fix it myself.

I have desperately tried to package the problem into an isolated test case instead but every attempt results in the process hanging even with 0.11.0. I tried mimicking what Resque does and then tried actually using Resque but I still couldn't replicate the behaviour I was seeing in my application. Rails or Adhearsion must be doing some other funky stuff around the edges.

For now, I have worked around the problem by adding :require => false to the Gemfile, only loading Adhearsion when starting Adhearsion itself. This meant losing the Adhearsion rake tasks but that wasn't a problem.

Still, I'd like to see this resolved properly. What I can tell you is that Celluloid seems to leave some sleeping threads behind because the actors never successfully terminate. I observed that terminate! is called on all of them but no further progress is made after the first Actor.join(actor). After two minutes (SHUTDOWN_TIMEOUT), the CPU usage shoots up. Oh, and I'm not sure but it looks like the Celluloid shutdown process actually starts as soon as Process.daemon is called for some reason.

Though not a proper fix, it might still be a good idea to make Celluloid more passive in the way it loads. I wouldn't expect a gem to do potentially hazardous things like start up new threads as soon as it is loaded. Adhearsion doesn't connect to a PBX as soon as it is loaded, for example. A method has to be called first. What do you think?

Celluloid needs a guaranteed-compatible mocking framework

Mocking frameworks can interfere with Celluloid in weird ways. To provide people a happy path where they won't have to deal with deadlocks that result from mocking framework interactions, create a guaranteed compatible mocking framework.

(Reference: #20, #22)

Celluloid::ThreadPool should support setting the max number of worker threads

I'd expect to be able to set the max number of worker threads for Celluloid::ThreadPool. I may be missing something, but there doesn't appear to be a way to limit the thread count.

From my understanding: If a thread was to enqueue a few thousand Futures and none completed before all were enqueued this would result in a few thousand threads! I'm a beginner to Ruby threading but I believe that will be costly.

Ruby error with Celluloid

/Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/tasks/task_fiber.rb:44: [BUG] Bus Error
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.4.2]

-- control frame ----------
c:0012 p:---- s:0040 b:0040 l:000039 d:000039 CFUNC :resume
c:0011 p:0018 s:0036 b:0036 l:000035 d:000035 METHOD /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/tasks/task_fiber.rb:44
c:0010 p:0066 s:0032 b:0032 l:000031 d:000031 METHOD /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/actor.rb:392
c:0009 p:0109 s:0026 b:0026 l:001810 d:001810 METHOD /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/actor.rb:320
c:0008 p:0046 s:0022 b:0022 l:000021 d:000021 METHOD /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/actor.rb:195
c:0007 p:0061 s:0017 b:0017 l:0007f8 d:000016 BLOCK /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/actor.rb:184
c:0006 p:0007 s:0015 b:0015 l:001368 d:000014 BLOCK /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/thread_handle.rb:12
c:0005 p:---- s:0013 b:0013 l:000012 d:000012 FINISH
c:0004 p:---- s:0011 b:0011 l:000010 d:000010 CFUNC :call
c:0003 p:0021 s:0008 b:0008 l:0002c8 d:000007 BLOCK /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/internal_pool.rb:48
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH

c:0001 p:---- s:0002 b:0002 l:000001 d:000001 TOP

-- Ruby level backtrace information ----------------------------------------
/Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/internal_pool.rb:48:in block in create' /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/internal_pool.rb:48:incall'
/Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/thread_handle.rb:12:in block in initialize' /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/actor.rb:184:inblock in initialize'
/Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/actor.rb:195:in run' /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/actor.rb:320:inhandle_message'
/Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/actor.rb:392:in task' /Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/tasks/task_fiber.rb:44:inresume'
/Users/blanchma/.rvm/gems/ruby-1.9.2-p290@deviceservice/gems/celluloid-0.12.0/lib/celluloid/tasks/task_fiber.rb:44:in `resume'

-- C level backtrace information -------------------------------------------
0 libruby.1.9.1.dylib 0x000000010bb0533d rb_vm_bugreport + 109
1 libruby.1.9.1.dylib 0x000000010b9f80f1 report_bug + 241
2 libruby.1.9.1.dylib 0x000000010b9f7ff5 rb_bug + 165
3 libruby.1.9.1.dylib 0x000000010ba9a422 sigbus + 18
4 libsystem_c.dylib 0x00007fff8eb57cfa _sigtramp + 26
5 ??? 0x000000010bdb1290 0x0 + 4493873808

[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

do not work with daemons

require 'celluloid'
require 'daemons'

class A 
  include Celluloid

  def daemon
    d = lambda do
      puts 1
      sleep 30
      puts 2
      exit
    end        

    Daemonize.call_as_daemon(d, "/tmp/1.log", 'name')
  end
end

a = A.new
a.daemon

sleep 1000
E, [2012-09-29T22:40:47.051172 #6081] ERROR -- : A crashed!
SystemExit: exit
/home/kostya/.rvm/gems/ruby-1.9.3-p194/gems/daemons-1.1.9/lib/daemons/daemonize.rb:65:in `exit'
/home/kostya/.rvm/gems/ruby-1.9.3-p194/gems/daemons-1.1.9/lib/daemons/daemonize.rb:65:in `call_as_daemon'
15.rb:15:in `daemon'
/home/kostya/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.12.0/lib/celluloid/calls.rb:57:in `dispatch'
/home/kostya/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.12.0/lib/celluloid/actor.rb:320:in `block in handle_message'
/home/kostya/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.12.0/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'
I, [2012-09-29T22:40:47.053251 #6081]  INFO -- : Shutdown completed cleanly

Celluloid::Actor missing #alive? in 0.12.0

NoMethodError: undefined method `alive?' for #<Celluloid::Actor:0x007f9062be36e8>
/Users/ben/code/punchblock/vendor/ruby/1.9.1/gems/celluloid-0.12.0/lib/celluloid.rb:245:in `alive?'

Still trying to figure out a minimal reproduction to make this clearer, and hard dependencies between celluloid-io and celluloid are making bisecting difficult.

How do pools work?

I would expect the following to handle the raise by restarting workers in the pool, and for "Hello" to be output 10 times.

require 'celluloid'

class MyWorker
  include Celluloid

  def run
    puts "Hello"
    raise
  end
end

pool = MyWorker.pool(size: 2)
10.times do
  pool.run!
end

sleep

Instead I get the following:

Hello
E, [2012-07-20T20:57:13.578637 #22533] ERROR -- : MyWorker crashed!
RuntimeError: 
pool.rb:8:in `run'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/calls.rb:57:in `dispatch'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor.rb:240:in `block in handle_message'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/task.rb:45:in `block in initialize'
E, [2012-07-20T20:57:13.579321 #22533] ERROR -- : Celluloid::PoolManager: async call `method_missing' aborted!
Celluloid::AbortError: caused by RuntimeError: 
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid.rb:212:in `abort'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/pool_manager.rb:26:in `rescue in _send_'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/pool_manager.rb:29:in `_send_'
/Users/xavier/.rvm/gems/ruby-1.9.3-Hello
p194/gems/celluloid-0.11.1/lib/celluloid/pool_manager.rb:80:in `method_missing'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/calls.rb:99:in `dispatch'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor.rb:240:in `block in handle_message'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/task.rb:45:in `block in initialize'
E, [2012-07-20T20:57:13.579773 #22533] ERROR -- : MyWorker crashed!
RuntimeError: 
pool.rb:8:in `run'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/calls.rb:57:in `dispatch'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor.rb:240:in `block in handle_message'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/task.rb:45:in `block in initialize'
E, [2012-07-20T20:57:13.580192 #22533] ERROR -- : Celluloid::PoolManager: async call `method_missing' aborted!
Celluloid::AbortError: caused by RuntimeError: 
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid.rb:212:in `abort'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/pool_manager.rb:26:in `rescue in _send_'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/pool_manager.rb:29:in `_send_'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/pool_manager.rb:80:in `method_missing'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/calls.rb:99:in `dispatch'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor.rb:240:in `block in handle_message'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/task.rb:45:in `block in initialize'
E, [2012-07-20T20:57:13.580539 #22533] ERROR -- : Celluloid::PoolManager: async call `method_missing' aborted!
Celluloid::AbortError: caused by #<Celluloid::DeadActorError: attempted to call a dead actor>: attempted to call a dead actor
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid.rb:212:in `abort'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/pool_manager.rb:26:in `rescue in _send_'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/pool_manager.rb:29:in `_send_'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/pool_manager.rb:80:in `method_missing'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/calls.rb:99:in `dispatch'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor.rb:240:in `block in handle_message'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/task.rb:45:in `block in initialize'

The process is then hung. After first CTRL-C:

^CI, [2012-07-20T20:57:44.117584 #22533]  INFO -- : Terminating 4 actors...

Then second:

^C/Users/xavier/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/thread.rb:71:in `sleep': Interrupt
    from /Users/xavier/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/thread.rb:71:in `wait'
    from /Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/mailbox.rb:71:in `receive'
    from /Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor.rb:68:in `call'
    from /Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor_proxy.rb:100:in `method_missing'
    from /Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid.rb:90:in `block (2 levels) in shutdown'
    from /Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid.rb:88:in `each'
    from /Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid.rb:88:in `block in shutdown'
    from /Users/xavier/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/timeout.rb:68:in `timeout'
    from /Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid.rb:73:in `shutdown'
    from /Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid.rb:101:in `block in <module:Celluloid>'
E, [2012-07-20T20:58:02.110619 #22533] ERROR -- : Celluloid::PoolManager crashed!
RuntimeError: 
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/task.rb:57:in `resume'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/task.rb:57:in `resume'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor.rb:240:in `handle_message'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor.rb:174:in `run'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/actor.rb:125:in `block in initialize'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/thread_handle.rb:12:in `block in initialize'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/internal_pool.rb:48:in `call'
/Users/xavier/.rvm/gems/ruby-1.9.3-p194/gems/celluloid-0.11.1/lib/celluloid/internal_pool.rb:48:in `block in create'

Then I have to background the process and kill -9 it :(

On the bang convention

From the wiki:

Adding a bang to a method name is a convention in Ruby used to indicate that the method is in some way "dangerous", and in Celluloid this is no exception. You have no guarantees that just because you made an asynchronous call it was ever actually invoked. Asynchronous calls will never raise an exception, even if an exception occurs when the receiver is processing it. Worse, unhandled exceptions will crash the receiver, and making an asynchronous call to a crashed object will not raise an error.

Still, I don't like how Celluloid uses bangs. Why?

  1. It just feels wrong.
  2. I suspect it will break methods that already have bangs.
  3. Going async deserves more "heads up" than just adding a bang.

So, instead of:

charlie.set_status! "asynchronously winning!"

Why not use:

charlie.async_set_status "asynchronously winning!"

Or:

charlie.set_status_async "asynchronously winning!"

Or:

charlie.async(:set_status, "asynchronously winning!")

Or -- not sure if this could be made to work, however:

async { charlie.set_status, "asynchronously winning!" }

Can't define bang methods in Celluloid classes

I have an available class with many banged predicate methods (end with !), and I want to make it asynchronous.
For example:

class Fruit
  include Celluloid
  def eat!
    p 'being eaten!' 
  end
end

Whenever I call the method Fruit#eat!, it will raise an exception:

Fruit: async call `eat' failed!
NoMethodError: undefined method `eat' for #<Celluloid::Actor(Fruit:0x63fc)>

I think it will be better if we can detect that the async method missing and call the correct demanded method.
Or a better scope based method call like DelayedJob will completely solve the naming conflict problem in this example:

class Fruit
  include Celluloid

  def eat
    p 'being eaten safely' 
  end

  def eat!
    p 'being eaten dangerous!' 
  end
end

My suggestion is:

f = Fruit.new
f.async.eat
# Or 
f.async.eat!

Thanks.

#inspect goes into infinite loop

An actor that has an ivar to an object that contains a circular reference to the same actor will go into an infinite loop when #inspect is called on the actor.

Support call stacks that don't fit in a Fiber on MRI/YARV

See: sidekiq/sidekiq#115

Celluloid uses Fibers to execute all methods. There are cases where the 4k call stack provided by Fibers on MRI/YARV are insufficient, and Celluloid should have a strategy to deal with these cases. I'm not going to just say "4kB should be good enough for anyone" because I respect there are a lot of use cases where 4kB is legitimately insufficient (although you might consider switching to JRuby or Rubinius)

A basic mitigation strategy is to use defer { ... } around the code that's exceeding the call stack limit. Using defer will run the code in a background thread, still providing synchronous semantics from the actor's point of view. However, this probably isn't the greatest solution as it requires 2 threads where we could use one.

Celluloid supports some special semantics through #exclusive. Methods dispatched entirely in exclusive mode don't need a fiber because they can't be suspended.

I think the best solution for this problem is to be able to declaratively mark methods as exclusive, e.g.:

class Foo
  include Celluloid
  exclusive :bar

  def bar
    ...
  end
end

Methods known to be exclusive can be executed directly in the root fiber and won't be subject to fiber stack limits. However they are subject to potential deadlocks if they call out to other actors that in turn attempt to "reenter" the caller.

Odd behavior with terminate

I'm seeing instances where I call actor.terminate if actor.alive? and I get a Celluloid::Task::TerminatedError in response. Is this a reasonable response? If I'm asking you to terminate an actor and you know it's already terminated, why not just make it a no-op?

/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.9.0/lib/celluloid/task.rb:23:in `suspend'
/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.9.0/lib/celluloid/actor.rb:38:in `call'
/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.9.0/lib/celluloid/actor_proxy.rb:13:in `send'
/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.9.0/lib/celluloid/actor_proxy.rb:60:in `terminate'
/Users/mperham/src/sidekiq/lib/sidekiq/manager.rb:44:in `block (2 levels) in stop'

I'm also seeing an instance where I have an actor with 5 messages queued in his mailbox, I terminate it and it continues to process those 5 messages before finally dying. Any ideas?

Unable to CTRL-C out of app

I'm unable to ctrl-c out of my celluloid app after hitting it with jmeter for a couple seconds using 1 thread. I've been able to reproduce this on both ubuntu 12.04 and os x 10.7 with ruby 1.9.3p194. I don't have this issue with jruby-1.6.7.

Error

^CI, [2012-08-21T23:59:45.412060 #43256]  INFO -- : Terminating 9 actors...
E, [2012-08-21T23:59:45.418773 #43256] ERROR -- : Celluloid::PoolManager: async call `method_missing' aborted!
Celluloid::Task::TerminatedError: task was terminated
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:36:in `suspend'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/task.rb:19:in `suspend'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:310:in `sleep'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid.rb:324:in `sleep'
foofoo.rb:66:in `do_something'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/calls.rb:57:in `dispatch'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:320:in `block in handle_message'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'
E, [2012-08-21T23:59:45.421058 #43256] ERROR -- : Celluloid::PoolManager: async call `method_missing' aborted!
Celluloid::Task::TerminatedError: task was terminated
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:36:in `suspend'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/task.rb:19:in `suspend'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:310:in `sleep'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid.rb:324:in `sleep'
foofoo.rb:66:in `do_something'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/calls.rb:57:in `dispatch'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:320:in `block in handle_message'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'
E, [2012-08-21T23:59:45.422937 #43256] ERROR -- : Celluloid::PoolManager: async call `method_missing' aborted!
Celluloid::Task::TerminatedError: task was terminated
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:36:in `suspend'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/task.rb:19:in `suspend'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:310:in `sleep'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid.rb:324:in `sleep'
foofoo.rb:66:in `do_something'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/calls.rb:57:in `dispatch'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:320:in `block in handle_message'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'
E, [2012-08-21T23:59:45.424840 #43256] ERROR -- : Celluloid::PoolManager: async call `method_missing' aborted!
Celluloid::Task::TerminatedError: task was terminated
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:36:in `suspend'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/task.rb:19:in `suspend'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:310:in `sleep'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid.rb:324:in `sleep'
foofoo.rb:66:in `do_something'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/calls.rb:57:in `dispatch'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:320:in `block in handle_message'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'

^C/Users/omnix/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/thread.rb:71:in `sleep': Interrupt
    from /Users/omnix/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/thread.rb:71:in `wait'
    from /Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/thread_handle.rb:35:in `block in join'
    from <internal:prelude>:10:in `synchronize'
    from /Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/thread_handle.rb:35:in `join'
    from /Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:159:in `join'
    from /Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid.rb:61:in `block (2 levels) in shutdown'
    from /Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid.rb:59:in `each'
    from /Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid.rb:59:in `block in shutdown'
    from /Users/omnix/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/timeout.rb:68:in `timeout'
    from /Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid.rb:44:in `shutdown'
    from /Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid.rb:72:in `block in <module:Celluloid>'
E, [2012-08-21T23:59:51.019989 #43256] ERROR -- : Celluloid::PoolManager crashed!
RuntimeError: 
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:44:in `resume'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/tasks/task_fiber.rb:44:in `resume'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:392:in `task'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:320:in `handle_message'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:195:in `run'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/actor.rb:184:in `block in initialize'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/thread_handle.rb:12:in `block in initialize'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/internal_pool.rb:48:in `call'
/Users/omnix/.rvm/gems/ruby-1.9.3-p194/bundler/gems/celluloid-092c27e7676a/lib/celluloid/internal_pool.rb:48:in `block in create'
^C^C^C^C^C^C
^C

App

require 'celluloid/io'

class Server
  include Celluloid::IO

  def initialize(host, port)
    puts "Server is up"
    @server = TCPServer.new(host, port)
    Celluloid::Actor[:pool] = Foo.pool
    run!
  end

  def finalize
    @server.close
  end

  def run
    loop { handle_connection! @server.accept }
  end

  def handle_connection(socket)
    connection = Connection.new(socket)
    begin
      connection.read_request
    end while connection.alive?
  rescue EOFError
    # Client disconnected prematurely
    # FIXME: should probably do something here
  end
end

class Connection    
  BUFFER_SIZE = 4096

  def initialize(socket)
    @socket = socket
    @keepalive = true
    @xml_request = ''
  end

  # Is the connection still active?
  def alive?; @keepalive; end

  def read_request
    begin
      @xml_request << @socket.readpartial(BUFFER_SIZE)
      if @xml_request.include?('</foo>')
        Celluloid::Actor[:pool].do_something!
        @socket.write 'RESPONSE'
        @keepalive = false
        @socket.close
      end
    rescue IOError, Errno::ECONNRESET, Errno::EPIPE
      @keepalive = false
      @socket.close unless @socket.closed?
      return
    end
  end

end

class Foo
  include Celluloid

  def do_something
    sleep 1
  end
end

Server.supervise('0.0.0.0', 4323)
sleep

Terminating a working actor causes crash

^CI, [2012-02-18T19:51:35.056764 #62323]  INFO -- : Shutting down
I, [2012-02-18T19:51:35.066260 #62323]  INFO -- : Pausing 5 seconds to allow workers to finish...
E, [2012-02-18T19:51:43.739123 #62323] ERROR -- : Sidekiq::Manager crashed!
Celluloid::DeadActorError: attempted to call a dead actor
/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.8.0/lib/celluloid/responses.rb:22:in `value'
/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.8.0/lib/celluloid/actor.rb:183:in `handle_message'
/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.8.0/lib/celluloid/actor.rb:130:in `run'
/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.8.0/lib/celluloid/actor.rb:89:in `block in initialize'
/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.8.0/lib/celluloid/thread_pool.rb:46:in `call'
/Users/mperham/.rvm/gems/ruby-1.9.3-p125@sidekiq/gems/celluloid-0.8.0/lib/celluloid/thread_pool.rb:46:in `block in create'

In this case, the actors are just sleeping for 10 seconds. After 5 seconds, Sidekiq calls terminate on all busy actors. The stack trace results (that's the entire trace).

uninitialized constant Celluloid::Logger when running rspec in a project using Celluloid on jruby

When running rspec in a project that uses Celluloid, rspec running fails because of a Celluloid uninit constant error:

$ rspec spec/workers/instance/test.restart_worker.rb 
NameError: uninitialized constant Celluloid::Logger
    const_missing at org/jruby/RubyModule.java:2642
        Celluloid at /Users/splittingred/.rvm/gems/jruby-1.6.7.2/gems/celluloid-0.11.0/lib/celluloid.rb:7
           (root) at /Users/splittingred/.rvm/gems/jruby-1.6.7.2/gems/celluloid-0.11.0/lib/celluloid.rb:5
          require at org/jruby/RubyKernel.java:1042
          require at /Users/splittingred/.rvm/rubies/jruby-1.6.7.2/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:60
          require at /Users/splittingred/.rvm/rubies/jruby-1.6.7.2/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:55
           (root) at /Users/splittingred/.rvm/gems/jruby-1.6.7.2/gems/celluloid-0.11.0/lib/celluloid.rb:3
          require at org/jruby/RubyKernel.java:1042
          require at /Users/splittingred/.rvm/rubies/jruby-1.6.7.2/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36
           (root) at /www/cloud-agent/spec/spec_helper.rb:1
             load at org/jruby/RubyKernel.java:1068
  load_spec_files at /www/cloud-agent/spec/workers/instance/test.restart_worker.rb:780
          collect at org/jruby/RubyArray.java:2339
  load_spec_files at /Users/splittingred/.rvm/gems/jruby-1.6.7.2/gems/rspec-core-2.11.1/lib/rspec/core/configuration.rb:780
              run at /Users/splittingred/.rvm/gems/jruby-1.6.7.2/gems/rspec-core-2.11.1/lib/rspec/core/command_line.rb:22
              run at /Users/splittingred/.rvm/gems/jruby-1.6.7.2/gems/rspec-core-2.11.1/lib/rspec/core/runner.rb:69
          autorun at /Users/splittingred/.rvm/gems/jruby-1.6.7.2/gems/rspec-core-2.11.1/lib/rspec/core/runner.rb:8

rspec runs fine as long as Celluloid is not required. Relevant gems installed:

activemodel (3.2.8)
activesupport (3.2.8)
celluloid (0.11.0)
celluloid-io (0.11.0)
celluloid-zmq (0.11.0)
dcell (0.11.0)
ffi (1.1.5 java)
ffi-rzmq (0.9.6)
jruby-launcher (1.0.15 java)
jruby-openssl (0.7.7)
reel (0.0.2)
rubygems-bundler (1.0.6)
rvm (1.11.3.5)

Can provide more info if needed.

Q: short-lived celluloid actors?

Sorry, let me know if it's inappropriate to ask general questions (rather than report bugs/feature requests) in the tracker, I couldn't find a listserv or any other recommended place to ask questions, and couldn't quite figure out from the docs or examples this general question about celluloid's intended uses (so you could consider this a documentation feature request!):

I am getting the feeling, but I'm not sure, that Celluloid does not intend you to have short-lived actors.

Like, I have some (possibly-multi-step) task that I will want to perform concurrently -- one possibility would be creating an Actor, interacting it with it to get things done, and then getting rid of the actor when I'm done. (Just let it go out of scope? Have to call some #shutdown or #terminate method on it first?). Later, there will be another one of these, do it again, instantiate a new Actor, repeat.

I get the sense that this is not what Celluloid intends, and the performance characteristics are going to be very poor. I get the sense that Celluloid's intended use case is very long-lived actors, which are basically 'workers' -- when you have a task to complete, you ask a worker to do it, but when it's done, the worker/actor is left running, and when you have work to do later, you ask the same worker/actor to do some more.

But I'm not sure, it's just sort of an intuitive sense from trying to look at how celluloid works, nothing I could find in docs or comments explicitly says this. Can you clarify the intended usage patterns?

The two approaches require somewhat different API designs within your actors themselves (what methods the actor has and what state it keeps how, esp cause a worker may be asked to perform more work when it's still in the middle of doing something else), as well as what state you keep the actor object itself in, so it'll end up 'persistent'. For the "actors should be long-lived" style, the WorkerPool approach is particularly useful -- the one the wiki says a built-in solution for is only in HEAD and not yet in a release -- any ETA on when there will be an official release including it?

Thanks for any advice! Sorry again if this if the wrong venue for such a question, feel free to direct me elsewhere!

Deadlock in Celluloid::Pool#get on OS X Lion

Running the Pool specs on Lion, w/ Ruby 1.9.3:

Running all specs
Run options: include {:focus=>true}

Celluloid::Pool
  gets actors from the pool (FAILED - 1)
  gets and automatically returns actors with a block (PENDING: No reason given)
  returns actors to the pool (PENDING: No reason given)
  knows the number of running actors
  knows the number of idle actors (PENDING: No reason given)
  tracks the number of idle actors properly even in the event of crashes (PENDING: No reason given)

Pending:
  Celluloid::Pool gets and automatically returns actors with a block
    # No reason given
    # ./spec/celluloid/pool_spec.rb:20
  Celluloid::Pool returns actors to the pool
    # No reason given
    # ./spec/celluloid/pool_spec.rb:34
  Celluloid::Pool knows the number of idle actors
    # No reason given
    # ./spec/celluloid/pool_spec.rb:46
  Celluloid::Pool tracks the number of idle actors properly even in the event of crashes
    # No reason given
    # ./spec/celluloid/pool_spec.rb:54

Failures:

  1) Celluloid::Pool gets actors from the pool
     Failure/Error: subject.get.should be_working
     fatal:
       deadlock detected
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/1.9.1/thread.rb:71:in `sleep'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/1.9.1/thread.rb:71:in `wait'
     # ./lib/celluloid/mailbox.rb:69:in `receive'
     # ./lib/celluloid/actor.rb:41:in `call'
     # ./lib/celluloid/actor_proxy.rb:80:in `method_missing'
     # ./spec/celluloid/pool_spec.rb:17:in `block (2 levels) in <top (required)>'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/example.rb:80:in `instance_eval'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/example.rb:80:in `block in run'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/example.rb:173:in `with_around_hooks'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/example.rb:77:in `run'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/example_group.rb:355:in `block in run_examples'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/example_group.rb:351:in `map'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/example_group.rb:351:in `run_examples'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/example_group.rb:337:in `run'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/command_line.rb:28:in `block (2 levels) in run'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/command_line.rb:28:in `map'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/command_line.rb:28:in `block in run'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/reporter.rb:34:in `report'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/command_line.rb:25:in `run'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/runner.rb:69:in `run'
     # /Users/ben/Developer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/rspec-core-2.9.0/lib/rspec/core/runner.rb:10:in `block in autorun'

Finished in 0.0467 seconds
6 examples, 1 failure, 4 pending

Failed examples:

rspec ./spec/celluloid/pool_spec.rb:16 # Celluloid::Pool gets actors from the pool
I, [2012-03-30T20:37:32.223323 #24249]  INFO -- : Terminating 4 actors...
I, [2012-03-30T20:37:32.225166 #24249]  INFO -- : Shutdown completed cleanly

All of the examples marked pending are so because they hang indefinitely otherwise. It should be noted that this is not necessarily a Ruby bug, since usage of ConditionVariable#wait in other projects works just fine (github.com/adhearsion/future-resource for example).

Silent failure when trying to bang a private method

Does nothing, not even a backtrace or message:

class ImagePipeline
  include Celluloid

  def process(url)
    me.scrape_page!(url)
  end

  private

  def scrape_page(url)
    result = open url
  end

  def me
    Celluloid.current_actor
  end
end

pipeline = ImagePipeline.new
pipeline.process 'http://blog.carbonfive.com'

Technically I just want to expose process() as a public method, the rest of the methods are internal steps within the pipeline.

Library appears to initialize and clean up when not explicitly instantiated

A simple script like this:

require 'celluloid'

outputs the following upon execution/exit:

I, [2012-09-20T11:34:13.727047 #13173]  INFO -- : Terminating 2 actors...
I, [2012-09-20T11:34:13.727431 #13173]  INFO -- : Shutdown completed cleanly

Shouldn't requiring a library be a fairly passive action, meaning that nothing should be initialized or cleaned up unless an object is created from that library?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.