Timeout::Extensions
The Timeout::Extensions Gem augments Ruby's timeout.rb
API with support for
multiple timeout backends which can be mixed and matched within a single app.
It supports pluggable timeout implementations which can selectively hook into multiple backend schedulers rather than resorting to running code in a separate thread to implement timeouts when there's a better backend available.
Installation
Add this line to your application's Gemfile:
gem 'timeout-extensions'
And then execute:
$ bundle
Or install it yourself as:
$ gem install timeout-extensions
Usage
The Timeout::Extensions gem enhances the Ruby standard library's
timeout.rb
API:
require 'timeout'
Timeout.timeout(30) do
# Times out after 30 seconds raising Timeout::Error
end
However, where timeout.rb
provides one implementation, the Timeout Gem
provides support for multiple, swappable backends:
# examples/even_odd.rb
require "timeout/extensions"
module MyAwesomeJob
def self.perform
timeout(5) do
sleep 5 # perform incredibly heavy job
end
rescue => e
puts "job failed: #{e.}"
end
end
module MyOwnTimeout
CustomTimeoutError = Class.new(RuntimeError)
def self.call(sec, *)
puts "pretending to wait for #{sec} seconds..."
yield
end
end
5.times.map do |i|
Thread.start do
Thread.current.timeout_handler = MyOwnTimeout
MyAwesomeJob.perform
end
end.join(&:join)
__END__
You can also setup a timeout backend temporarily, for the duration of a block:
Timeout.backend(MyTimeoutThingy) do
Timeout.timeout(30) do
# Manage timeouts with MyTimeoutThingy instead of timeout.rb
# MyTimeoutThingy just responds to #call(sec, ex)
# Plug in your own backend just this easily!
end
end
This library also supports setting your own sleep implementation:
Thread.start do
Thread.current.sleep_handler = YourSleepHandler # must also respond to #call(Integer or nil)
....
Celluloid Support
This gem provides celluloid support out of the box.
Celluloid has its own actor timeout and sleep methods, which are implemented using the timer
gem and do not block its mailbox. These have to be called inside your celluloid actor context however, thereby limiting the scope of your code:
# examples/celluloid.rb
require "celluloid"
module MyJob
def self.perform
puts "performing"
sleep 5
puts "performed!"
end
end
class Worker
include Celluloid
def develop
MyJob.perform
end
def ten_times_developer
10.times.each { async(:develop) }
end
end
Worker.new.async(:ten_times_developer)
sleep
__END__
But if your had the extension in the first line:
require 'timeout/extensions/celluloid'
....
__END__
performing
performing
performing
performing
performing
performing
performing
performing
performing
performing
performed!
performed!
performed!
performed!
performed!
....
Supported Ruby Versions
This library aims to support and is [tested against][travis] the following Ruby versions:
- Ruby 2.1
- Ruby 2.2
- Ruby 2.3
- JRuby 9.1
If something doesn't work on one of these versions, it's a bug.
Contributing
- Fork this repository on github
- Make your changes and send us a pull request
- If we like them we'll merge them
- If we've accepted a patch, feel free to ask for commit access
License
Copyright (c) 2014-2016 Tony Arcieri, Tiago Cardoso Distributed under the MIT License. See LICENSE.txt for further details.