Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/manuelmeurer/tries
Solidify your code and retry on petty exceptions
https://github.com/manuelmeurer/tries
retry retry-strategies
Last synced: about 1 month ago
JSON representation
Solidify your code and retry on petty exceptions
- Host: GitHub
- URL: https://github.com/manuelmeurer/tries
- Owner: manuelmeurer
- License: mit
- Created: 2012-11-24T12:25:35.000Z (about 12 years ago)
- Default Branch: master
- Last Pushed: 2020-02-20T12:02:48.000Z (almost 5 years ago)
- Last Synced: 2024-10-08T08:21:13.282Z (2 months ago)
- Topics: retry, retry-strategies
- Language: Ruby
- Homepage:
- Size: 43.9 KB
- Stars: 52
- Watchers: 4
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Tries
[![Gem Version](https://badge.fury.io/rb/tries.png)](http://badge.fury.io/rb/tries)
[![Build Status](https://secure.travis-ci.org/manuelmeurer/tries.png)](http://travis-ci.org/manuelmeurer/tries)Solidify your code and retry on petty exceptions.
Tries lets you retry a block of code multiple times, which is convenient for example when communicating with external APIs that might return an error the one second but work fine the next.
You can specify exactly how often the block of code is retried and which exceptions are caught.
## Requirements
Tests run on Ruby >= 2.5 is tested, older versions might work as well.
## Installation
Add this line to your application's Gemfile:
gem 'tries'
And then execute:
$ bundle
Or install it yourself as:
$ gem install tries
## Usage
```ruby
3.tries on: Timeout::Error do
Mechanize.new.get 'https://www.google.com/'
end
```## Detailed usage
### Helper code to explain how it works
```ruby
FooError = Class.new(StandardError)
BarError = Class.new(StandardError)@error_counter = 0
def method_that_raises_exception
@error_counter += 1
puts "Counter is #{@error_counter}"case @error_counter
when 1 then raise FooError, 'retry'
when 2 then raise FooError, 'retry'
when 3 then raise BarError
when 4 then raise StandardError
endputs 'You made it through!'
end
```### Rescue all errors
```ruby
4.tries do
method_that_raises_exception
end# => Counter is 1
# => Counter is 2
# => Counter is 3
# => Counter is 4
# => Counter is 5
# => You made it through!
```### Rescue a specific error
```ruby
3.tries on: FooError do
method_that_raises_exception
end# => Counter is 1
# => Counter is 2
# => Counter is 3
# => BarError
```### Rescue multiple errors
```ruby
3.tries on: [FooError, BarError] do
method_that_raises_exception
end# => Counter is 1
# => Counter is 2
# => Counter is 3
# => Counter is 4
# => StandardError
```### Rescue error on condition
```ruby
3.tries if: ->(error) { error.message == 'retry' } do
method_that_raises_exception
end# => Counter is 1
# => Counter is 2
# => Counter is 3
# => BarError
```### Delay execution after error
`delay` is in seconds, fractions are possible
#### Static delay
```ruby
4.tries delay: 1.5 do
method_that_raises_exception
end# => Counter is 1
# waits 1.5 seconds...
# => Counter is 2
# waits 1.5 seconds...
# => Counter is 3
# waits 1.5 seconds...
# => Counter is 4
# waits 1.5 seconds...
# => Counter is 5
# => You made it through!
```#### Incremental delay
```ruby
4.tries delay: 1.5, incremental: true do
method_that_raises_exception
end# => Counter is 1
# waits 1.5 seconds...
# => Counter is 2
# waits 3 seconds...
# => Counter is 3
# waits 4.5 seconds...
# => Counter is 4
# waits 6 seconds...
# => Counter is 5
# => You made it through!
```### Callback on error
You can set a method or Proc to be called every time an exception occurs. Either set it globally in an initializer, e.g. to log all exceptions to a service like [Airbrake](https://airbrake.io/), or locally when calling `tries`. If both a global callback and a local callback are set, both are called, the global one first.
#### Global callback
```ruby
# config/initializers/tries.rb
Tries.configure do |config|
config.on_error = lambda do |exception, attempts, next_delay|
puts "Whow, a #{exception.class} just occurred! It was attempt nr. #{attempts} to do whatever I was doing."
if next_delay
puts "I'm gonna wait #{next_delay} seconds and try again."
else
puts "A delay was not configured so I'm gonna go for it again immediately."
end
end
end
``````ruby
3.tries delay: 0.5, incremental: true do
method_that_raises_exception
end# => Counter is 1
# => Whow, a FooError just occurred! It was attempt nr. 1 to do whatever I was doing.
# => I'm gonna wait 0.5 seconds and try again.
# waits 0.5 seconds...
# => Counter is 2
# => Whow, a FooError just occurred! It was attempt nr. 2 to do whatever I was doing.
# => I'm gonna wait 1.0 seconds and try again.
# waits 1 second...
# => Counter is 3
# => Whow, a BarError just occurred! It was attempt nr. 3 to do whatever I was doing.
# => I'm gonna wait 1.5 seconds and try again.
# waits 1.5 seconds...
# => Counter is 4
# => StandardError
```When using Rails, a global callback also lets you effectively disable Tries in development environment:
```ruby
# config/initializers/tries.rb
Tries.configure do |config|
config.on_error = lambda do |exception, attempts, next_delay|
raise exception if Rails.env.development?
end
end
```#### Local callback
```ruby
callback = lambda do |exception, attempts, next_delay|
puts "Local callback! Exception: #{exception.class}, attempt: #{attempts}, next_delay: #{next_delay}"
end3.tries delay: 0.5, incremental: true, on_error: callback do
method_that_raises_exception
end# => Counter is 1
# => Local callback! Exception: FooError, attempt: 1, next_delay: 0.5
# waits 0.5 seconds...
# => Counter is 2
# => Local callback! Exception: FooError, attempt: 2, next_delay: 1.0
# waits 1 second...
# => Counter is 3
# => Local callback! Exception: BarError, attempt: 3, next_delay: 1.5
# waits 1.5 seconds...
# => Counter is 4
# => StandardError
```## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request## Support
If you like this project, consider [buying me a coffee](https://www.buymeacoffee.com/279lcDtbF)! :)