dirty_pipeline 0.8.3 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c994b31257ebb9f48ae2c67ce0d197027f9397ad407944d9f938dabf80dbbe58
4
- data.tar.gz: 16684ec82ac970097e7add8f2a80e4d45d929d118d0cd88ef8e3584c3f478df0
3
+ metadata.gz: 000ac5cab919b0a6781a640b60a54163ce802a3c1c30a84e937a9ea1f8368e01
4
+ data.tar.gz: e45766b16965674ac64bd3f8c1d494435ca1af9538cc0fb229ac596c845ee28d
5
5
  SHA512:
6
- metadata.gz: 99ef4a8cc4ce384654c8fc90c1b5bec987955512c942c0c82bac630034e02f8df2ad26ef03f7f7dab961456b24399f6adaa443ccbcf50a0f9a858ea82f5aeb2f
7
- data.tar.gz: 8482d89667c2ba8906fe553928c37e969256b1db6be91b25364d7d1f1ab5cf253fc8fc5f6ad15e8ef81afc30ba8b07a839ada7d46056571a21d4b0f1aa29e155
6
+ metadata.gz: 124a17b8c4b59bbccfc90a7ca7d0bc2c8e6abbad1827db2f875643251e5b34dfbef8a66d39272b89ef775d4b9d2e43981411d8b334f8edb9401087beb4e3b4cb
7
+ data.tar.gz: 1fa1006ed40dddece9300d713b86d1c1fc934a775e9653615af91162a25dce92b63b9e5ebfce29d0dbfe51370f49bbb2bb415803532526d2282a253867db52cc
@@ -42,12 +42,16 @@ module DirtyPipeline
42
42
  @status = Status.success(subject)
43
43
  end
44
44
 
45
- def find_transition(name)
46
- self.class.transitions_map.fetch(name.to_s).tap do |from:, **kwargs|
47
- next unless railway.operation.eql?(:call)
48
- next if from == Array(storage.status)
49
- next if from.include?(storage.status.to_s)
50
- raise InvalidTransition, "from `#{storage.status}` by `#{name}`"
45
+ def find_transition!(event)
46
+ tname = event.transition
47
+ event.source = storage.status
48
+ self.class.transitions_map.fetch(tname.to_s).tap do |from:, **kwargs|
49
+ next unless railway.operation.eql?("call")
50
+ next if from == Array(event.source)
51
+ next if from.include?(event.source.to_s)
52
+ raise InvalidTransition, "from `#{event.source}` by `#{tname}`"
53
+ end.tap do |to:, **|
54
+ event.destination = to if railway.operation.eql?("call")
51
55
  end
52
56
  end
53
57
 
@@ -128,12 +132,14 @@ module DirtyPipeline
128
132
  def execute(event, attempt_retry: false)
129
133
  attempt_retry ? event.attempt_retry! : event.start!
130
134
 
131
- # dispatch event?
132
- Transaction.new(self, event).call do |destination, action, *args|
135
+ Transaction.new(self, event).call do |action, *args|
133
136
  state_changes = process_action(action, event, *args)
137
+
134
138
  event.assign_changes(state_changes)
139
+ event.complete if event.start?
140
+
135
141
  next if status.failure?
136
- Success(event, destination)
142
+ Success(event)
137
143
  end
138
144
  call_next
139
145
 
@@ -177,8 +183,7 @@ module DirtyPipeline
177
183
  @status = Status.failure(cause, tag: type)
178
184
  end
179
185
 
180
- def Success(event, destination)
181
- event.complete(destination)
186
+ def Success(event)
182
187
  @status = Status.success(subject)
183
188
  end
184
189
  end
@@ -23,6 +23,15 @@ module DirtyPipeline
23
23
  )
24
24
  end
25
25
 
26
+ def dup
27
+ self.class.new(
28
+ data: data.merge(
29
+ "uuid" => SecureRandom.uuid,
30
+ "status" => NEW,
31
+ )
32
+ )
33
+ end
34
+
26
35
  attr_reader :id, :tx_id, :error, :data
27
36
  def initialize(options = {}, data: nil, error: nil)
28
37
  unless options.empty?
@@ -54,6 +63,22 @@ module DirtyPipeline
54
63
  {data: @data, error: @error}
55
64
  end
56
65
 
66
+ def source
67
+ data["source"]
68
+ end
69
+
70
+ def source=(value)
71
+ data["source"] = value
72
+ end
73
+
74
+ def destination
75
+ data["destination"]
76
+ end
77
+
78
+ def destination=(value)
79
+ data["destination"] = value
80
+ end
81
+
57
82
  %w(args transition cache destination changes).each do |method_name|
58
83
  define_method("#{method_name}") { @data[method_name] }
59
84
  end
@@ -90,9 +115,8 @@ module DirtyPipeline
90
115
  @data["changes"] = changes
91
116
  end
92
117
 
93
- def complete(destination)
118
+ def complete
94
119
  @data.merge!(
95
- "destination" => destination,
96
120
  "updated_at" => Time.now.utc.iso8601,
97
121
  "status" => SUCCESS,
98
122
  )
@@ -139,6 +139,8 @@ module DirtyPipeline
139
139
  "txid" => event.tx_id,
140
140
  "transit" => event.transition,
141
141
  "args" => event.args,
142
+ "source" => event.source,
143
+ "destination" => event.destination
142
144
  )
143
145
  end
144
146
 
@@ -151,6 +153,8 @@ module DirtyPipeline
151
153
  "transaction_uuid" => unpacked_event["txid"],
152
154
  "transition" => unpacked_event["transit"],
153
155
  "args" => unpacked_event["args"],
156
+ "source" => unpacked_event["source"],
157
+ "destination" => unpacked_event["destination"]
154
158
  }
155
159
  )
156
160
  end
@@ -1,7 +1,7 @@
1
1
  module DirtyPipeline
2
2
  module PG
3
3
  class Railway
4
- DEFAULT_OPERATIONS = %w(call undo finalize)
4
+ DEFAULT_OPERATIONS = %w(call undo finalize finalize_undo)
5
5
 
6
6
  def self.create!(connection)
7
7
  connection.exec <<~SQL
@@ -59,7 +59,7 @@ module DirtyPipeline
59
59
  DO UPDATE SET data = EXCLUDED.data, error = EXCLUDED.error;
60
60
  SQL
61
61
  def commit!(event)
62
- store["status"] = event.destination if event.destination
62
+ store["status"] = event.destination if event.success?
63
63
  store["state"].merge!(event.changes) unless event.changes.to_h.empty?
64
64
  data, error = {}, {}
65
65
  data = event.data.to_h if event.data.respond_to?(:to_h)
@@ -52,6 +52,8 @@ module DirtyPipeline
52
52
  "txid" => event.tx_id,
53
53
  "transit" => event.transition,
54
54
  "args" => event.args,
55
+ "source" => event.source,
56
+ "destination" => event.destination,
55
57
  )
56
58
  end
57
59
 
@@ -64,6 +66,8 @@ module DirtyPipeline
64
66
  "transaction_uuid" => unpacked_event["txid"],
65
67
  "transition" => unpacked_event["transit"],
66
68
  "args" => unpacked_event["args"],
69
+ "source" => unpacked_event["source"],
70
+ "destination" => unpacked_event["destination"]
67
71
  }
68
72
  )
69
73
  end
@@ -48,7 +48,7 @@ module DirtyPipeline
48
48
  end
49
49
 
50
50
  def commit!(event)
51
- store["status"] = event.destination if event.destination
51
+ store["status"] = event.destination if event.success?
52
52
  store["state"].merge!(event.changes) unless event.changes.to_h.empty?
53
53
 
54
54
  error = {}
@@ -12,16 +12,15 @@ module DirtyPipeline
12
12
  pipeline.schedule_cleanup
13
13
 
14
14
  # Split attempts config and event dispatching
15
- destination, action, max_attempts_count =
16
- pipeline.find_transition(event.transition)
17
- .values_at(:to, :action, :attempts)
15
+ action, max_attempts_count =
16
+ pipeline.find_transition!(event).values_at(:action, :attempts)
18
17
 
19
18
  storage.commit!(event)
20
19
 
21
20
  # FIXME: make configurable, now - hardcoded to AR API
22
21
  # subject.transaction(requires_new: true) do
23
22
  subject.transaction do
24
- with_abort_handling { yield(destination, action, *event.args) }
23
+ with_abort_handling { yield(action, *event.args) }
25
24
  end
26
25
  rescue => exception
27
26
  event.link_exception(exception)
@@ -1,4 +1,6 @@
1
1
  module DirtyPipeline
2
+ class Rollback < StandardError; end
3
+
2
4
  class Transition
3
5
  def Failure(error)
4
6
  railway&.switch_to(:undo)
@@ -7,6 +9,10 @@ module DirtyPipeline
7
9
 
8
10
  def Success(changes = nil)
9
11
  case railway&.active
12
+ when "finalize_undo"
13
+ railway&.switch_to(:undo)
14
+ when "undo"
15
+ railway&.switch_to(:finalize_undo) if respond_to?(:finalize_undo)
10
16
  when "call"
11
17
  railway&.switch_to(:finalize) if respond_to?(:finalize)
12
18
  when "finalize"
@@ -15,6 +21,13 @@ module DirtyPipeline
15
21
  throw :success, changes.to_h
16
22
  end
17
23
 
24
+ def self.finalize_undo(*args, **kwargs)
25
+ event, pipeline, *args = args
26
+ instance = new(event, pipeline.railway, *args, **kwargs)
27
+ return unless instance.respond_to?(:finalize_undo)
28
+ instance.finalize_undo(pipeline.subject)
29
+ end
30
+
18
31
  def self.finalize(*args, **kwargs)
19
32
  event, pipeline, *args = args
20
33
  instance = new(event, pipeline.railway, *args, **kwargs)
@@ -25,6 +38,7 @@ module DirtyPipeline
25
38
  def self.undo(*args, **kwargs)
26
39
  event, pipeline, *args = args
27
40
  instance = new(event, pipeline.railway, *args, **kwargs)
41
+ pipeline&.railway&.send(:[], :finalize_undo)&.send(:<<, event)
28
42
  return unless instance.respond_to?(:undo)
29
43
  instance.undo(pipeline.subject)
30
44
  end
@@ -32,11 +46,18 @@ module DirtyPipeline
32
46
  def self.call(*args, **kwargs)
33
47
  event, pipeline, *args = args
34
48
  instance = new(event, pipeline.railway, *args, **kwargs)
35
- pipeline&.railway&.send(:[], :undo)&.send(:<<, event)
36
49
  pipeline&.railway&.send(:[], :finalize)&.send(:<<, event)
50
+ prepare_undo(pipeline, event)
37
51
  instance.call(pipeline.subject)
38
52
  end
39
53
 
54
+ def self.prepare_undo(pipeline, event)
55
+ anti_event = event.dup
56
+ anti_event.source, anti_event.destination =
57
+ event.destination, event.source
58
+ pipeline&.railway&.send(:[], :undo)&.send(:unshift, anti_event)
59
+ end
60
+
40
61
  attr_reader :event, :railway
41
62
  def initialize(event, railway, *, **)
42
63
  @event = event
@@ -1,3 +1,3 @@
1
1
  module DirtyPipeline
2
- VERSION = "0.8.3"
2
+ VERSION = "0.9.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dirty_pipeline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergey Dolganov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-09 00:00:00.000000000 Z
11
+ date: 2019-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq