Security News
PyPI’s New Archival Feature Closes a Major Security Gap
PyPI now allows maintainers to archive projects, improving security and helping users make informed decisions about their dependencies.
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.
Ruby >= 1.9.2
Add this line to your application's Gemfile:
gem 'tries'
And then execute:
$ bundle
Or install it yourself as:
$ gem install tries
3.tries on: Timeout::Error do
Mechanize.new.get 'https://www.google.com/'
end
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
end
puts 'You made it through!'
end
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!
3.tries on: FooError do
method_that_raises_exception
end
# => Counter is 1
# => Counter is 2
# => Counter is 3
# => BarError
3.tries on: [FooError, BarError] do
method_that_raises_exception
end
# => Counter is 1
# => Counter is 2
# => Counter is 3
# => Counter is 4
# => StandardError
3.tries if: ->(error) { error.message == 'retry' } do
method_that_raises_exception
end
# => Counter is 1
# => Counter is 2
# => Counter is 3
# => BarError
delay
is in seconds, fractions are possible
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!
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!
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, or locally when calling tries
. If both a global callback and a local callback are set, both are called, the global one first.
# 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
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:
# 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
callback = lambda do |exception, attempts, next_delay|
puts "Local callback! Exception: #{exception.class}, attempt: #{attempts}, next_delay: #{next_delay}"
end
3.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
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)If you like this project, consider buying me a coffee! :)
FAQs
Unknown package
We found that tries demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PyPI now allows maintainers to archive projects, improving security and helping users make informed decisions about their dependencies.
Research
Security News
Malicious npm package postcss-optimizer delivers BeaverTail malware, targeting developer systems; similarities to past campaigns suggest a North Korean connection.
Security News
CISA's KEV data is now on GitHub, offering easier access, API integration, commit history tracking, and automated updates for security teams and researchers.