Skip to content

Commit

Permalink
Call before_retry when retrying indefinitely
Browse files Browse the repository at this point in the history
  • Loading branch information
Joao Fernandes authored and jeremyevans committed Feb 11, 2020
1 parent 244a241 commit 40bd336
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 9 deletions.
14 changes: 5 additions & 9 deletions lib/sequel/database/transactions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def rollback_checker(opts=OPTS)
# :num_retries :: The number of times to retry if the :retry_on option is used.
# The default is 5 times. Can be set to nil to retry indefinitely,
# but that is not recommended.
# :before_retry :: Proc to execute before rertrying if the :retry_on option is used.
# :before_retry :: Proc to execute before retrying if the :retry_on option is used.
# Called with two arguments: the number of retry attempts (counting
# the current one) and the error the last attempt failed with.
# :prepare :: A string to use as the transaction identifier for a
Expand Down Expand Up @@ -178,19 +178,15 @@ def transaction(opts=OPTS, &block)
opts = Hash[opts]
if retry_on = opts[:retry_on]
tot_retries = opts.fetch(:num_retries, 5)
num_retries = 0 unless tot_retries.nil?
num_retries = 0
begin
opts[:retry_on] = nil
opts[:retrying] = true
transaction(opts, &block)
rescue *retry_on => e
if num_retries
num_retries += 1
if num_retries <= tot_retries
opts[:before_retry].call(num_retries, e) if opts[:before_retry]
retry
end
else
num_retries += 1
if tot_retries.nil? || num_retries <= tot_retries
opts[:before_retry].call(num_retries, e) if opts[:before_retry]
retry
end
raise
Expand Down
13 changes: 13 additions & 0 deletions spec/core/database_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,19 @@ def db.supports_savepoints?; true end
calls.must_equal [1, 2]
end

it "should support :before_retry option for invoking callback before retrying when doing it indefinitely" do
a, errs, calls = [], [], []
retryer = proc{|n, err| calls << n; errs << err }
@db.transaction(:num_retries => nil, :retry_on=>Sequel::DatabaseDisconnectError, :before_retry => retryer) do
a << 1; raise Sequel::DatabaseDisconnectError if a.length < 3
end
@db.sqls.must_equal ['BEGIN', 'ROLLBACK', 'BEGIN', 'ROLLBACK', 'BEGIN', 'COMMIT']
a.must_equal [1, 1, 1]
errs.count.must_equal 2
errs.each { |e| e.class.must_equal Sequel::DatabaseDisconnectError }
calls.must_equal [1, 2]
end

it "should raise an error if attempting to use :retry_on inside another transaction" do
proc{@db.transaction{@db.transaction(:retry_on=>Sequel::ConstraintViolation){}}}.must_raise(Sequel::Error)
@db.sqls.must_equal ['BEGIN', 'ROLLBACK']
Expand Down

0 comments on commit 40bd336

Please sign in to comment.