Skip to content

Instantly share code, notes, and snippets.

@ericallam
Created July 30, 2017 10:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericallam/368b0e96999b74d35abca4a0a98b06cb to your computer and use it in GitHub Desktop.
Save ericallam/368b0e96999b74d35abca4a0a98b06cb to your computer and use it in GitHub Desktop.
ApplicationService running a retryable REPEATABLE READ transaction
def call(form, attempts_count = 0, &block)
return block.call(form).unwrap unless transaction_handler.enabled?
return transaction_handler.transaction { block.call(form).unwrap } if nested_transaction_detector.call
if attempts_count < max_attempts
begin
attempts_count = attempts_count + 1
transaction_handler.transaction(isolation: :repeatable_read) { block.call(form, attempt: attempts_count).unwrap }
rescue Survivor::Adapters::Error => error
if error.respond_to?(:cause) && error.cause.is_a?(ActiveRecord::StatementInvalid) && error.cause.cause.message.include?("could not serialize access due to concurrent update")
form.errors.clear
call(form, attempts_count, &block)
else
raise error
end
end
else
raise UncommittableRepeatableReadTransactionError.new(max_attempts)
end
end
def call(form)
repeatable_transaction(form) do |form, attempt: 1, outcome: Outcome.new|
capture { validate form }
.then { create_transfer form, outcome }
.then { activate_entry form, outcome }
.then { outcome.transfer }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment