mirror of
https://github.com/aasm/aasm
synced 2023-03-27 23:22:41 -04:00
Add use transaction flag
This commit is contained in:
parent
6f493c4553
commit
c5b7efaab2
7 changed files with 73 additions and 2 deletions
18
README.md
18
README.md
|
@ -957,6 +957,24 @@ end
|
||||||
|
|
||||||
which then leads to `transaction(:requires_new => false)`, the Rails default.
|
which then leads to `transaction(:requires_new => false)`, the Rails default.
|
||||||
|
|
||||||
|
Additionally, if you do not want any of your active record actions to be
|
||||||
|
wrapped in a transaction, you can specify the `use_transactions` flag. This can
|
||||||
|
be useful if you want want to persist things to the database that happen as a
|
||||||
|
result of a transaction or callback, even when some error occurs. The
|
||||||
|
`use_transactions` flag is true by default.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class Job < ActiveRecord::Base
|
||||||
|
include AASM
|
||||||
|
|
||||||
|
aasm :use_transactions => false do
|
||||||
|
...
|
||||||
|
end
|
||||||
|
|
||||||
|
...
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
### Pessimistic Locking
|
### Pessimistic Locking
|
||||||
|
|
||||||
AASM supports [Active Record pessimistic locking via `with_lock`](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html#method-i-with_lock) for database persistence layers.
|
AASM supports [Active Record pessimistic locking via `with_lock`](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html#method-i-with_lock) for database persistence layers.
|
||||||
|
|
|
@ -26,6 +26,9 @@ module AASM
|
||||||
# raise if the model is invalid (in ActiveRecord)
|
# raise if the model is invalid (in ActiveRecord)
|
||||||
configure :whiny_persistence, false
|
configure :whiny_persistence, false
|
||||||
|
|
||||||
|
# Use transactions (in ActiveRecord)
|
||||||
|
configure :use_transactions, true
|
||||||
|
|
||||||
# use requires_new for nested transactions (in ActiveRecord)
|
# use requires_new for nested transactions (in ActiveRecord)
|
||||||
configure :requires_new_transaction, true
|
configure :requires_new_transaction, true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,9 @@ module AASM
|
||||||
# for ActiveRecord: store the new state even if the model is invalid and return true
|
# for ActiveRecord: store the new state even if the model is invalid and return true
|
||||||
attr_accessor :skip_validation_on_save
|
attr_accessor :skip_validation_on_save
|
||||||
|
|
||||||
|
# for ActiveRecord: use transactions
|
||||||
|
attr_accessor :use_transactions
|
||||||
|
|
||||||
# for ActiveRecord: use requires_new for nested transactions?
|
# for ActiveRecord: use requires_new for nested transactions?
|
||||||
attr_accessor :requires_new_transaction
|
attr_accessor :requires_new_transaction
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,10 @@ module AASM
|
||||||
AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.skip_validation_on_save
|
AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.skip_validation_on_save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def use_transactions?(state_machine_name)
|
||||||
|
AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.use_transactions
|
||||||
|
end
|
||||||
|
|
||||||
def requires_new?(state_machine_name)
|
def requires_new?(state_machine_name)
|
||||||
AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.requires_new_transaction
|
AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.requires_new_transaction
|
||||||
end
|
end
|
||||||
|
@ -118,7 +122,11 @@ module AASM
|
||||||
event.fire_global_callbacks(:before_all_transactions, self, *args)
|
event.fire_global_callbacks(:before_all_transactions, self, *args)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
success = aasm_transaction(requires_new?(state_machine_name), requires_lock?(state_machine_name)) do
|
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
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ ActiveRecord::Migration.suppress_messages do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(transactors no_lock_transactors lock_transactors lock_no_wait_transactors multiple_transactors).each do |table_name|
|
%w(transactors no_lock_transactors lock_transactors lock_no_wait_transactors no_transactors multiple_transactors).each do |table_name|
|
||||||
ActiveRecord::Migration.create_table table_name, :force => true do |t|
|
ActiveRecord::Migration.create_table table_name, :force => true do |t|
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.string "status"
|
t.string "status"
|
||||||
|
|
|
@ -72,6 +72,31 @@ class LockNoWaitTransactor < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class NoTransactor < ActiveRecord::Base
|
||||||
|
|
||||||
|
belongs_to :worker
|
||||||
|
|
||||||
|
include AASM
|
||||||
|
aasm :column => :status, use_transactions: false do
|
||||||
|
state :sleeping, :initial => true
|
||||||
|
state :running, :before_enter => :start_worker, :after_enter => :fail
|
||||||
|
|
||||||
|
event :run do
|
||||||
|
transitions :to => :running, :from => :sleeping
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def start_worker
|
||||||
|
worker.update_attribute(:status, 'running')
|
||||||
|
end
|
||||||
|
|
||||||
|
def fail
|
||||||
|
raise StandardError.new('failed on purpose')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class MultipleTransactor < ActiveRecord::Base
|
class MultipleTransactor < ActiveRecord::Base
|
||||||
|
|
||||||
belongs_to :worker
|
belongs_to :worker
|
||||||
|
|
|
@ -506,6 +506,20 @@ if defined?(ActiveRecord)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'without transactions' do
|
||||||
|
let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
|
||||||
|
let(:no_transactor) { NoTransactor.create!(:name => 'transactor', :worker => worker) }
|
||||||
|
|
||||||
|
it 'should not rollback all changes' do
|
||||||
|
expect(no_transactor).to be_sleeping
|
||||||
|
expect(worker.status).to eq('sleeping')
|
||||||
|
|
||||||
|
expect {no_transactor.run!}.to raise_error(StandardError, 'failed on purpose')
|
||||||
|
expect(no_transactor).to be_running
|
||||||
|
expect(worker.reload.status).to eq('running')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'transactions' do
|
describe 'transactions' do
|
||||||
let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
|
let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
|
||||||
let(:transactor) { Transactor.create!(:name => 'transactor', :worker => worker) }
|
let(:transactor) { Transactor.create!(:name => 'transactor', :worker => worker) }
|
||||||
|
|
Loading…
Add table
Reference in a new issue