Closed marshall-lee closed 8 years ago
I'm not getting this error if at least one these conditions met:
Celluloid
instead of Celluloid::IO
(but it's useless with celluloid-ruby
, right?)IOError
manually instead of calling redis.incr
(fails but restarts)Redis
with default driver (without driver: :celluloid
)And also I noticed that if I change push
method this way:
def push
redis.incr 'var'
raise IOError
rescue
puts 'oh no!'
p $!
puts $!.backtrace
raise
end
then it fails instantly on the first call to push
but it doesn't restart. And without redis.incr 'var'
call it restarts fine as I mentioned above.
Maybe celluloid-ruby
is somehow not thread safe but why the supervised actor is not restarted?
Have you tried it with
require 'celluloid/redis'
yet ?
Also,
def redis
@redis ||= Redis.new(driver: :celluloid)
end
doesn't look safe, can you try it to setup the redis object in the initializer?
require 'celluloid/redis'
just loads redis-ext
that monkeypatches _parse_driver
. And also it fails: NoMethodError: undefined method 'new' for Celluloid::Redis:Module
.
But this monkeypatch is not required now since _parse_driver
from redis-rb
calls require
dynamically
Okay, I changed my example to this:
require 'celluloid/current'
require 'celluloid/io'
require 'celluloid/redis'
class RedisPusher
include Celluloid::IO
def initialize
@redis = ::Redis.new(driver: :celluloid)
end
attr_reader :redis
def push
redis.incr 'var'
rescue
puts 'oh no!'
p $!
puts $!.backtrace
raise
end
end
class Worker
include Celluloid
def initialize
async.work
end
def work
sleep 1
loop do
30.times do
Celluloid::Actor[:pusher].async.push
end
sleep 0.5
end
rescue
p $!
retry
end
end
RedisPusher.supervise as: :pusher
Worker.supervise as: :worker
sleep
And it still fails.
NoMethodError: undefined method 'new' for Celluloid::Redis:Module
It's just a minor issue in celluloid-redis
— it defines Celluloid::Redis
module in version.rb
, don't pay attention to this for now.
Btw, why @redis ||= Redis.new(driver: :celluloid)
is not threadsafe?
Simpler example (without race) that fails and doesn't restart supervisor too:
require 'celluloid/current'
require 'celluloid/io'
require 'celluloid/redis'
class RedisPusher
include Celluloid::IO
def initialize
@redis = ::Redis.new(driver: :celluloid)
end
attr_reader :redis
def push
redis.incr 'var'
raise IOError
rescue
puts 'oh no!'
p $!
puts $!.backtrace
raise
end
end
RedisPusher.supervise as: :pusher
Celluloid::Actor[:pusher].async.push
sleep 0.1
Celluloid::Actor[:pusher].async.push
Second call to async.push
fails with this error:
undefined method `async' for nil:NilClass (NoMethodError)
Example without celluloid-redis
at all:
require 'celluloid/current'
require 'celluloid/io'
class Server
include Celluloid::IO
finalizer :shutdown
def initialize
system('rm -f /tmp/something')
@server = UNIXServer.new('/tmp/something')
async.run
end
def run
loop { async.handle_connection @server.accept }
end
def handle_connection(socket)
loop { socket.write socket.readpartial(4096) }
rescue EOFError
socket.close
end
def shutdown
@server.close if @server
end
end
class Client
include Celluloid::IO
def initialize
@socket = UNIXSocket.new('/tmp/something')
end
def push(str)
@socket.write str
puts @socket.read
raise IOError
end
end
Server.supervise as: :server
Client.supervise as: :client
Celluloid::Actor[:client].async.push('1')
sleep 0.1
Celluloid::Actor[:client].async.push('2')
Also fails with:
undefined method
async' for nil:NilClass (NoMethodError)`
Also without @socket.read
supervised actor restarts fine.
must have mistaken
def redis
@redis ||= Redis.new(driver: :celluloid)
end
with
def self.redis
@redis ||= Redis.new(driver: :celluloid)
end
The latter is not thread safe.
sorry ^^
Btw, if you want to throw a exception but don't crash a actor you can use fail IOError
@Asmod4n simple explanation is here: https://github.com/celluloid/celluloid/pull/666#issuecomment-134156510
should be fixed by https://github.com/celluloid/celluloid/pull/666
Not sure if it's a right repo for reporting this but here it is.
I'm trying to use
celluloid-redis
inside ofCelluloid::IO
actor.And after some amout of time i'm getting this error:
As you can see
Celluloid::Actor[:pusher]
does not restart!