(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
"requiring version.rb" strategy has some issues.
- cannot work when cross-compiling
- often introduces wrong namespace
- must know the superclasses
- costs at each runtime than at build-time
etc.
If uplevel keyword is given, the warning message is prepended
with caller file and line information and the string "warning: ".
The use of the uplevel keyword makes Kernel#warn format output
similar to how rb_warn formats output.
This patch modifies net/ftp and net/imap to use Kernel#warn
instead of $stderr.puts or $stderr.printf, since they are used
for printing warnings.
This makes lib/cgi/core and tempfile use $stderr.puts instead of
warn for debug logging, since they are used for debug printing
and not for warning.
This does not modify bundler, rubygems, or rdoc, as those are
maintained outside of ruby and probably wish to remain backwards
compatible with older ruby versions.
rb_warn_m code is originally from nobu, but I've changed it
so that it only includes the path and lineno from uplevel
(not the method), and also prepends the string "warning: ",
to make it more similar to rb_warn.
From: Jeremy Evans code@jeremyevans.net
Signed-off-by: Urabe Shyouhei shyouhei@ruby-lang.org
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61155 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/timeout.rb (Timeout#timeout): set watcher thread name to
caller location for debugging.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53195 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
When you change this to true, you may need to add more tests.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53141 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* variable.c (rb_const_get_0): warn deprecated constant reference.
* variable.c (rb_mod_deprecate_constant): mark constants to be
warned as deprecated. [Feature #11398]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51444 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/timeout.rb (Timeout): get rid of an argument prefix warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/timeout.rb (timeout): warn as deprecated for a long time.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51226 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/timeout.rb (ExitException): removed internal exception class
and use Timeout::Error instead, as using throw/catch to isolate
each timeouts now. [ruby-dev:49179] [Bug #11344]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51213 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/timeout.rb (Timeout::ExitException.catch): do not freeze the
exception for tag, so that the same object can be passed to the
target fiber without duplication to attach backtrace at raise.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48467 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/timeout.rb (Timeout::ExitException#exception): rescue
UncaughtThrowError which is specific for throw, instead of
ArgumentError.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48460 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/timeout.rb (Timeout::ExitException.catch): pass arguments
for new instance.
* lib/timeout.rb (Timeout::ExitException#exception): fallback to
Timeout::Error if couldn't throw. [ruby-dev:47872] [Bug #9380]
* lib/timeout.rb (Timeout#timeout): initialize ExitException with
message for the fallback case.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44523 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/timeout.rb (Timeout#timeout): should not rescue ordinarily
raised ExitException, which should not be thrown.
* lib/timeout.rb (Timeout::ExitException.catch): set @thread only if
it ought to be caught.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44518 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/timeout.rb (Timeout#timeout): when a custom exception is given,
no instance is needed to be caught, so defer creating new instance
until it is raised. [ruby-core:59511] [Bug #9354]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44517 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* NEWS: Improve grammar on change to Timeout
Patched by @srawlins in https://github.com/ruby/ruby/pull/440
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43640 b2dd03c8-39d4-4d8f-98ff-823fe69b080e