-
Notifications
You must be signed in to change notification settings - Fork 23
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
Thread.handle_interrupt results in an unpredictable behavior since #15 #41
Comments
jpcamara
added a commit
to jpcamara/ruby
that referenced
this issue
Aug 29, 2024
* This PR from the timeout gem (ruby/timeout#30) made it so you have to handle_interrupt on Timeout::ExitException instead of Timeout::Error * Efficiency changes to the gem (one shared thread) mean you can't consistently handle timeout errors using handle_timeout: ruby/timeout#41
jpcamara
added a commit
to jpcamara/ruby
that referenced
this issue
Aug 29, 2024
* This PR from the timeout gem (ruby/timeout#30) made it so you have to handle_interrupt on Timeout::ExitException instead of Timeout::Error * Efficiency changes to the gem (one shared thread) mean you can't consistently handle timeout errors using handle_timeout: ruby/timeout#41
jpcamara
added a commit
to jpcamara/ruby
that referenced
this issue
Aug 29, 2024
* This PR from the timeout gem (ruby/timeout#30) made it so you have to handle_interrupt on Timeout::ExitException instead of Timeout::Error * Efficiency changes to the gem (one shared thread) mean you can't consistently handle timeout errors using handle_timeout: ruby/timeout#41
hsbt
pushed a commit
to ruby/ruby
that referenced
this issue
Sep 9, 2024
* This PR from the timeout gem (ruby/timeout#30) made it so you have to handle_interrupt on Timeout::ExitException instead of Timeout::Error * Efficiency changes to the gem (one shared thread) mean you can't consistently handle timeout errors using handle_timeout: ruby/timeout#41
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
tl; dr
Thread.handle_interrupt
won't work well when the timeout thread is reused. It is because blocked interrupts are inherited when the thread is created. In my opinion such an inheritance should not happen, but removing it will be a breaking change and requires core Ruby change.Long story
#15 changed Timeout to reuse a thread. On the other hand, a thread inherits the blocked interrupts of the creating thread. This means the list of blocked interrupts will persist once after a thread is created first time.
This breaks the code something like follows:
Code Y follows the example shown at: https://docs.ruby-lang.org/en/3.2/Thread.html#method-c-handle_interrupt-label-Guarding+from+Timeout-3A-3AError
In this case, the later
Thread.handle_interrupt(Timeout::Error => :never)
will have no effect.The opposite scenario can also happen. Consider the following code:
In my opinion, this kind of problem occurs due to a bad design of Ruby threads; a new thread should not inherit the blocked interrupts. The inheritance of blocked interrupts can break multithreading code so easily. Thread reuse as seen in Timeout is one of patterns affected by this design. Any kind of thread pools will also be affected.
The inheritance is also problematic when a method called from
Thread.handle_interrupt
block usesThread#raise
. For example, think of the following code:SomeExternalLibrary.gracefully_close_connection
may not work because timeout is blocked withThread.handle_interrupt(Object => :never)
.This kind of problems will not happen if the inheritance of blocked interrupts does not happen. Removing the inheritance of blocked interrupts would break code part Y, but I don't think that matters much. In fact, if you should be able to rewrite the code as follows:
If you still need to block
Timeout::Error
at the beginning of the timeout block, timeout method can have an extra parameter to block interrupts before the timer gets armed though I don't see a use case for that.That said, removing the inheritance of blocked interrupts will be a breaking change so it's not really practical. Also it will be a core Ruby change so timeout gem may need its own solution, perhaps just reverting #15, adding an option, or just edit the documentation to say "do not use timeout with
Thread.handle_interrupt
ever".The text was updated successfully, but these errors were encountered: