statesman 3.5.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/lib/statesman/adapters/active_record.rb +38 -2
- data/lib/statesman/machine.rb +3 -3
- data/lib/statesman/version.rb +1 -1
- data/lib/tasks/statesman.rake +1 -1
- data/spec/statesman/adapters/active_record_queries_spec.rb +34 -0
- data/spec/statesman/adapters/active_record_spec.rb +2 -0
- data/statesman.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5063951e126e3898569d97511ea5c89149122c3e
|
4
|
+
data.tar.gz: 888fcdc8b6bfbde03dbc4471fa3d84f58fd0871e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4f1b64670d9b94c53f65ef3ed7182be77388c732536906d7066db8e0970016ad1e0cec26148d62b5cd32719e446a253033da3b1e8dd5c0c5e813834715e032f
|
7
|
+
data.tar.gz: 8c5ab391235a0f4b073fee60eeea93c4752e9f5a2d71a6b05ba955cebfd5bae61921bf87ac9769a967db05439cd907e5de6be1fe5f8d5a45a80fc4588b722d9a
|
data/.circleci/config.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## v4.0.0, 22 February 2019
|
2
|
+
|
3
|
+
- Forces Statesman to use a new transactions with `requires_new: true` (https://github.com/gocardless/statesman/pull/249)
|
4
|
+
- Fixes an issue with `after_commit` transition blocks that where being
|
5
|
+
executed even if the transaction rolled back. ([patch](https://github.com/gocardless/statesman/pull/338) by [@matid](https://github.com/matid))
|
6
|
+
|
1
7
|
## v3.5.0, 2 November 2018
|
2
8
|
|
3
9
|
- Expose `most_recent_transition_join` - ActiveRecords `or` requires that both
|
@@ -25,6 +25,7 @@ module Statesman
|
|
25
25
|
elsif serialized && JSON_COLUMN_TYPES.include?(column_type)
|
26
26
|
raise IncompatibleSerializationError, transition_class.name
|
27
27
|
end
|
28
|
+
|
28
29
|
@transition_class = transition_class
|
29
30
|
@parent_model = parent_model
|
30
31
|
@observer = observer
|
@@ -36,6 +37,7 @@ module Statesman
|
|
36
37
|
create_transition(from.to_s, to.to_s, metadata)
|
37
38
|
rescue ::ActiveRecord::RecordNotUnique => e
|
38
39
|
raise TransitionConflictError, e.message if transition_conflict_error? e
|
40
|
+
|
39
41
|
raise
|
40
42
|
ensure
|
41
43
|
@last_transition = nil
|
@@ -70,18 +72,26 @@ module Statesman
|
|
70
72
|
|
71
73
|
transition = transitions_for_parent.build(transition_attributes)
|
72
74
|
|
73
|
-
::ActiveRecord::Base.transaction do
|
75
|
+
::ActiveRecord::Base.transaction(requires_new: true) do
|
74
76
|
@observer.execute(:before, from, to, transition)
|
75
77
|
unset_old_most_recent
|
76
78
|
transition.save!
|
77
79
|
@last_transition = transition
|
78
80
|
@observer.execute(:after, from, to, transition)
|
81
|
+
add_after_commit_callback(from, to, transition)
|
79
82
|
end
|
80
|
-
@observer.execute(:after_commit, from, to, transition)
|
81
83
|
|
82
84
|
transition
|
83
85
|
end
|
84
86
|
|
87
|
+
def add_after_commit_callback(from, to, transition)
|
88
|
+
::ActiveRecord::Base.connection.add_transaction_record(
|
89
|
+
ActiveRecordAfterCommitWrap.new do
|
90
|
+
@observer.execute(:after_commit, from, to, transition)
|
91
|
+
end,
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
85
95
|
def transitions_for_parent
|
86
96
|
@parent_model.send(@association_name)
|
87
97
|
end
|
@@ -147,5 +157,31 @@ module Statesman
|
|
147
157
|
params.merge(column => timestamp)
|
148
158
|
end
|
149
159
|
end
|
160
|
+
|
161
|
+
class ActiveRecordAfterCommitWrap
|
162
|
+
def initialize
|
163
|
+
@callback = Proc.new
|
164
|
+
@connection = ::ActiveRecord::Base.connection
|
165
|
+
end
|
166
|
+
|
167
|
+
# rubocop: disable Naming/PredicateName
|
168
|
+
def has_transactional_callbacks?
|
169
|
+
true
|
170
|
+
end
|
171
|
+
# rubocop: enable Naming/PredicateName
|
172
|
+
|
173
|
+
def committed!(*)
|
174
|
+
@callback.call
|
175
|
+
end
|
176
|
+
|
177
|
+
def before_committed!(*); end
|
178
|
+
|
179
|
+
def rolledback!(*); end
|
180
|
+
|
181
|
+
# Required for +transaction(requires_new: true)+
|
182
|
+
def add_to_transaction(*)
|
183
|
+
@connection.add_transaction_record(self)
|
184
|
+
end
|
185
|
+
end
|
150
186
|
end
|
151
187
|
end
|
data/lib/statesman/machine.rb
CHANGED
data/lib/statesman/version.rb
CHANGED
data/lib/tasks/statesman.rake
CHANGED
@@ -19,7 +19,7 @@ namespace :statesman do
|
|
19
19
|
batch_size = 500
|
20
20
|
|
21
21
|
parent_class.find_in_batches(batch_size: batch_size) do |models|
|
22
|
-
ActiveRecord::Base.transaction do
|
22
|
+
ActiveRecord::Base.transaction(requires_new: true) do
|
23
23
|
if Statesman::Adapters::ActiveRecord.database_supports_partial_indexes?
|
24
24
|
# Set all transitions' most_recent to FALSE
|
25
25
|
transition_class.where(parent_fk => models.map(&:id)).
|
@@ -168,4 +168,38 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
|
|
168
168
|
end
|
169
169
|
end
|
170
170
|
end
|
171
|
+
|
172
|
+
context "after_commit transactional integrity" do
|
173
|
+
before do
|
174
|
+
MyStateMachine.class_eval do
|
175
|
+
cattr_accessor(:after_commit_callback_executed) { false }
|
176
|
+
|
177
|
+
after_transition(from: :initial, to: :succeeded, after_commit: true) do
|
178
|
+
# This leaks state in a testable way if transactional integrity is broken.
|
179
|
+
MyStateMachine.after_commit_callback_executed = true
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
after do
|
185
|
+
MyStateMachine.class_eval do
|
186
|
+
callbacks[:after_commit] = []
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
let!(:model) do
|
191
|
+
MyActiveRecordModel.create
|
192
|
+
end
|
193
|
+
|
194
|
+
# rubocop:disable RSpec/ExampleLength
|
195
|
+
it do
|
196
|
+
expect do
|
197
|
+
ActiveRecord::Base.transaction do
|
198
|
+
model.state_machine.transition_to!(:succeeded)
|
199
|
+
raise ActiveRecord::Rollback
|
200
|
+
end
|
201
|
+
end.to_not change(MyStateMachine, :after_commit_callback_executed)
|
202
|
+
end
|
203
|
+
# rubocop:enable RSpec/ExampleLength
|
204
|
+
end
|
171
205
|
end
|
@@ -227,6 +227,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
227
227
|
it "still has the old state" do
|
228
228
|
allow(observer).to receive(:execute) do |phase|
|
229
229
|
next unless phase == :before
|
230
|
+
|
230
231
|
expect(
|
231
232
|
model.transitions.where(most_recent: true).first.to_state,
|
232
233
|
).to eq("y")
|
@@ -240,6 +241,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
240
241
|
it "still has the old state" do
|
241
242
|
allow(observer).to receive(:execute) do |phase|
|
242
243
|
next unless phase == :after
|
244
|
+
|
243
245
|
expect(
|
244
246
|
model.transitions.where(most_recent: true).first.to_state,
|
245
247
|
).to eq("z")
|
data/statesman.gemspec
CHANGED
@@ -31,6 +31,6 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency "rspec-its", "~> 1.1"
|
32
32
|
spec.add_development_dependency "rspec-rails", "~> 3.1"
|
33
33
|
spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.0"
|
34
|
-
spec.add_development_dependency "sqlite3", "~> 1.3"
|
34
|
+
spec.add_development_dependency "sqlite3", "~> 1.3.6"
|
35
35
|
spec.add_development_dependency "timecop", "~> 0.9.1"
|
36
36
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statesman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GoCardless
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ammeter
|
@@ -184,14 +184,14 @@ dependencies:
|
|
184
184
|
requirements:
|
185
185
|
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version:
|
187
|
+
version: 1.3.6
|
188
188
|
type: :development
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version:
|
194
|
+
version: 1.3.6
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: timecop
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|