dirty_pipeline 0.8.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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