-
-
Notifications
You must be signed in to change notification settings - Fork 273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Timeout extensions #491
Timeout extensions #491
Conversation
…ler activate (unfortunately don't know how to do this for sleep)
…s the pool of threads used by celluloid actors
…le; the actor instance method therefore routes all cores there
…the timeout; Also removed a call to Kernel.sleep inside the Celluloid.sleep method, as I think that all calls inside the Celluloid namespace should me taking Celluloid into account and forget about the 'outer' world
…core timeout method; also made the ResumableError a behaviour instead of a full exception, thereby enabling decorating custom classes that can be passed to the timeout method
… do if sleep is called outside the actor context?
Need to get |
@tarcieri , I've noticed the celluloid refactorings recently. Are the timeout extensions being considered for any of the planned minor releases? |
@TiagoCardoso1983 given how invasive they are, I think I'd prefer to keep them out of core if possible. Perhaps this patch could be further modularized so that less of it depends on changes to Celluloid. |
I would argue that these changes are not that invasive, but correct some fundamental flaws to the "time" methods. For instance, Celluloid.timeout currently takes one argument instead of two, like ruby's Timeout::timeout. Besides that I don't see what you mean by invasive. |
Here is the all necessary monkey-patching needed for the extensions to work: module Celluloid
class Thread < ::Thread
def initialize(*)
self.timeout_handler = Celluloid.method(:timeout).to_proc
self.sleep_handler = Celluloid::method(:sleep).to_proc
super
end
end
def self.timeout(duration, klass = nil)
bt = caller
task = Task.current
klass ||= Task::TimeoutError
timers = Thread.current[:celluloid_actor].timers
timer = timers.after(duration) do
exception = klass.new("execution expired")
exception.set_backtrace bt
task.resume exception
end
yield
ensure
timer.cancel if timer
end
class Actor
def timeout(*args)
Celluloid::timeout(*args) { yield }
end
private :timeout
end
remove_const(:ResumableError)
module ResumableError ; end
class Task
remove_const(:TerminatedError)
remove_const(:TimeoutError)
class TerminatedError < Celluloid::Error; include ResumableError ;end
class TimeoutError < Celluloid::Error; include ResumableError ;end
end
end I could indeed puts this into a timeout-extensions celluloid script, but this looks like API which can be subject to change, and actually everything that timeout-extensions needs to work are those patches in the Thread class. The rest of it are just problems I had while using Celluloid::IO with some classes which call timeout with 2 arguments. |
Conflicts: Gemfile celluloid.gemspec lib/celluloid/actor.rb lib/celluloid/internal_pool.rb lib/celluloid/rspec/actor_examples.rb lib/celluloid/task.rb
@digitalextremist could you review this? This was under discussion with @tarcieri , but was forgotten in the whole 0.17 migration and was a bit in the limbo. Nevertheless, this addresses the timeout issue discussed under the sidekiq thread (Namely that plain ruby timeout calls break actors). There is currently one failing spec, and this has to due with the (again, discussed somewhere else) fact that TaskTimeout exceptions now inherit from Exception and can't be caught by the RSpec raise_error call (and again, this could also be the initial point for a rediscussion on that design decision, as I'm not particularly a fan of it). |
@TiagoCardoso1983 no problem. Will review. |
What are the performance implications of this additional layer of indirection? RubyDNS uses timeouts a lot in performance sensitive code for handling the (rare) case where the network doesn't respond in time. The overhead for timeouts that don't fire and are cancelled needs to be minimised at the expense of timeouts that do eventually fire, IMHO. |
@ioquatix I'm not sure that I understood. This pull request doesn't change the way celluloid works, it just "moves" the timeout BL to the Celluloid module. Why? Because it makes it easier to use here. I would argue that network not respond in time is not rare, and in the context of celluloid, you'd need to prevent the usage of the ruby timeout/sleep, which will block the actor message-processing. In the context of celluloid-io, which can be used to patch stdlib and other network libraries, which use Timeout.timeout extensively, that's even more important. |
Okay I will review. |
As you may have seen by now, this was applied to an ancient version of celluloid. It has been scattered across subgems as of 0.17, which makes this harder to track. What concerns celluloid, the parts I'd like to maintain in the pull request are migrating the BL of timeout to Celluloid module, where Celluloid.sleep is. I guess, since they're timer based tasks, it makes sense to have them close to each other and publicly acessible. The point of overhead you might have noticed comes from the thread pool spawner. This timeout/sleep overwrites have been discussed ages ago with @tarcieri . He was never fond of "monkey-patching" Kernel and Timeout.timeout (who is?), rather wanted to "push" the community to adopt the approach. I decided not to wait and have been using it in production in my company internal projects without significant issues (main issues: 1) Celluloid::Task::TimeoutError inherits from Exception instead of StandardError/Timeout::Error, makes rescu'ing a bitx; and 2) every call to sleep/timeout will have |
I completely agree with you on all points. We will try to resolve these issues for 0.18.0 including merging your changes. |
No worries, I just wanted to give you the history of this issue. |
… as it there was no timeout set
@HoneyryderChuck not sure if you're interested in picking this up. Many of the subgems are now unified again, which should make this change easier. |
@tarcieri haven't been using celluloid for a while, so this stopped becoming a priority for me. Besides that, I think the PR is sort of complete from my side, so it's a matter of it being worthy of being merged or not. I'm actually surprised there are no conflicts, given how much has changed... |
Absent a volunteer to carry this forward, I don't see this getting merged. If someone would like to continue this work, please create a new, up-to-date PR. |
Continuation of what's going on here. This is how I envisioned integrating the extensions into celluloid. Main changes are a few Exceptions, method signatures and the fact that the main timeout and sleep logic is directly inside the Celluloid module, instead of inside the actor.
Main discussion topics:
Thread.current[:celluloid_actor].timeout(duration)...: