1. Introduce State to store all status.
2. Store State instance to the Ractor local storage if possible
3. Make `GET_TIME` (Method object) shareable if possible
3 is supporeted Ruby 4.0 and later, so the Rator support is works
only on Ruby 4.0 and later.
https://github.com/ruby/timeout/commit/54ff671c6c
(https://github.com/ruby/timeout/pull/30)
throw/catch is used for non-local control flow, not for exceptional situations.
For exceptional situations, raise should be used instead. A timeout is an
exceptional situation, so it should use raise, not throw/catch.
Timeout's implementation that uses throw/catch internally causes serious problems.
Consider the following code:
```ruby
def handle_exceptions
yield
rescue Exception => exc
handle_error # e.g. ROLLBACK for databases
raise
ensure
handle_exit unless exc # e.g. COMMIT for databases
end
Timeout.timeout(1) do
handle_exceptions do
do_something
end
end
```
This kind of design ensures that all exceptions are handled as errors, and
ensures that all exits (normal exit, early return, throw/catch) are not
handled as errors. With Timeout's throw/catch implementation, this type of
code does not work, since a timeout triggers the normal exit path.
See https://github.com/rails/rails/pull/29333 for an example of the damage
Timeout's design has caused the Rails ecosystem.
This switches Timeout.timeout to use raise/rescue internally. It adds a
Timeout::ExitException subclass of exception for the internal raise/rescue,
which Timeout.timeout will convert to Timeout::Error for backwards
compatibility. Timeout::Error remains a subclass of RuntimeError.
This is how timeout used to work in Ruby 2.0. It was changed in Ruby 2.1,
after discussion in [Bug #8730] (commit
https://github.com/ruby/timeout/commit/238c003c921e in the timeout repository). I
think the change from using raise/rescue to using throw/catch has caused
significant harm to the Ruby ecosystem at large, and reverting it is
the most sensible choice.
From the translation of [Bug #8730], it appears the issue was that
someone could rescue Exception and not reraise the exception, causing
timeout errors to be swallowed. However, such code is broken anyway.
Using throw/catch causes far worse problems, because then it becomes
impossible to differentiate between normal control flow and exceptional
control flow.
Also related to this is [Bug #11344], which changed how
Thread.handle_interrupt interacted with Timeout.
https://github.com/ruby/timeout/commit/f16545abe6
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Don't move the timer_thread to ThreadGroup::Default, when it's
created in an enclosed ThreadGroup.
Prevents the exception: "add" can't move from the enclosed thread group"
https://github.com/ruby/timeout/commit/eb889d2c8b
`timeout 0.3.0` broke our test suite because we have some
tests that stubs `Process.clock_gettime` making it return
a value in the past, causing `Timeout` to trigger almost immediately.
I beleive it wasn't a problem before because it was relying on `Process.sleep`.
https://github.com/ruby/timeout/commit/e5911a303e
This makes:
raise(Timeout::Error.new("hello"), "world")
raise a TimeoutError instance with "world" as the message instead
of "hello", for consistency with other Ruby exception classes.
This required some internal changes to keep the tests passing.
Fixes [Bug #17812]
https://github.com/ruby/timeout/commit/952154dbf9