-
Notifications
You must be signed in to change notification settings - Fork 646
Description
Describe the bug
When there are multiple after_commit callbacks within nested transaction and an exception occurs, the last after_commit callback is not fired while others are.
To Reproduce
class Test < ApplicationRecord
include AASM
aasm column: :state, timestamp: false do
state :initial, initial: true
state :submitted, :accepted, :ready, :completed
event :submit, after: :after_submit, after_commit: :after_commit_submit do
transitions from: :initial, to: :submitted
end
event :accept, after: :after_accept, after_commit: :after_commit_accept do
transitions from: :submitted, to: :accepted
end
event :ready, after: :after_ready, after_commit: :after_commit_ready do
transitions from: :accepted, to: :ready
end
event :complete, after: :after_complete, after_commit: :after_commit_complete do
transitions from: :ready, to: :completed
end
end
def after_submit
ap "AFTER_SUBMIT"
accept!
end
def after_commit_submit
ap "AFTER_COMMIT_SUBMIT"
end
def after_accept
ap "AFTER_ACCEPT"
ready!
end
def after_commit_accept
ap "AFTER_COMMIT_ACCEPT"
end
def after_ready
ap "AFTER_READY"
complete!
end
def after_commit_ready
ap "AFTER_COMMIT_READY"
end
def after_complete
ap "AFTER_COMPLETE"
end
def after_commit_complete
ap "AFTER_COMMIT_COMPLETE"
raise "Oh my god, something's wrong!"
end
endwhen running Test.create!.submit!, after_commit_submit won't get called.
"AFTER_SUBMIT"
"AFTER_ACCEPT"
"AFTER_READY"
"AFTER_COMPLETE" --> innermost transaction is commited
"AFTER_COMMIT_COMPLETE"
"AFTER_COMMIT_READY"
"AFTER_COMMIT_ACCEPT"
# where is "AFTER_COMMIT_SUBMIT"? --> outermost callback not executed
Expected behavior
"AFTER_SUBMIT"
"AFTER_ACCEPT"
"AFTER_READY"
"AFTER_COMPLETE"
"AFTER_COMMIT_COMPLETE"
"AFTER_COMMIT_READY"
"AFTER_COMMIT_ACCEPT"
"AFTER_COMMIT_SUBMIT"
Screenshots
If applicable, add screenshots to help explain your problem.
Additional context
The root cause of this problem is that the first submit!'s aasm_transaction raises an exception originated from nested transaction (after_commit_complete) and fails to call aasm_execute_after_commit in the code below.
aasm/lib/aasm/persistence/orm.rb
Lines 129 to 149 in 666ef70
| begin | |
| success = if options[:persist] && use_transactions?(state_machine_name) | |
| aasm_transaction(requires_new?(state_machine_name), requires_lock?(state_machine_name)) do | |
| super | |
| end | |
| else | |
| super | |
| end | |
| if success && !(event.options.keys & [:after_commit, :after_all_commits]).empty? | |
| aasm_execute_after_commit do | |
| event.fire_callbacks(:after_commit, self, *args) | |
| event.fire_global_callbacks(:after_all_commits, self, *args) | |
| end | |
| end | |
| success | |
| ensure | |
| event.fire_callbacks(:after_transaction, self, *args) | |
| event.fire_global_callbacks(:after_all_transactions, self, *args) | |
| end |
If everyone sees this as an issue to be handled, I will work on a PR.
cc. @njw1204