ductwork 0.7.1 → 0.8.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/CHANGELOG.md +12 -0
- data/lib/ductwork/cli.rb +43 -31
- data/lib/ductwork/models/pipeline.rb +28 -39
- data/lib/ductwork/models/step.rb +2 -2
- data/lib/ductwork/processes/pipeline_advancer.rb +6 -2
- data/lib/ductwork/version.rb +1 -1
- data/lib/generators/ductwork/install/templates/db/create_ductwork_steps.rb +3 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f64abfa6d358cd7b225baae1b801894032936bef4de86ff0843e3163552aa530
|
|
4
|
+
data.tar.gz: aedd9daa71379091503375926ea4863a7834193a1701ee265a9b0b99a7fbfe50
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 85598e36b5edb64f33217d19cb2f2af66e6991c68f74c0a8ede9c445d88884bd804da2b381b2dd9cdeaa6a6936a340628af25c45ff259632f36d1c4429665bcb
|
|
7
|
+
data.tar.gz: 4f59ad232e7a00c8e34403dfb8412af7e7351f0d921b3fd7fc6c27ee10524a1bd37e57bd18aa020c9e7daf1c3374127927e54474302364f3ee6962d157b9e468
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Ductwork Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.0]
|
|
4
|
+
|
|
5
|
+
- chore: re-organize `Ductwork::CLI` class
|
|
6
|
+
- feat!: better name `ductwork_steps.step_type` to `to_transition` - the column rename is a breaking change but not bumping major version since the gem is still pre-1.0
|
|
7
|
+
- feat: add `delay_seconds` and `timeout_seconds` columns to `ductwork_steps` table
|
|
8
|
+
- feat: set pipeline status to `advancing` once pipeline is claimed and advancing starts
|
|
9
|
+
- chore: add `advancing` status enum value to `Pipeline`
|
|
10
|
+
|
|
11
|
+
## [0.7.2]
|
|
12
|
+
|
|
13
|
+
- chore: small DRY refactor in pipeline advancement
|
|
14
|
+
|
|
3
15
|
## [0.7.1]
|
|
4
16
|
|
|
5
17
|
- chore: isolate on halt execution in `Ductwork::Job#execution_failed!`
|
data/lib/ductwork/cli.rb
CHANGED
|
@@ -4,45 +4,57 @@ require "optparse"
|
|
|
4
4
|
|
|
5
5
|
module Ductwork
|
|
6
6
|
class CLI
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Ductwork.configuration = Configuration.new(**options)
|
|
11
|
-
Ductwork.logger = if Ductwork.configuration.logger_source == "rails"
|
|
12
|
-
Rails.logger
|
|
13
|
-
else
|
|
14
|
-
Ductwork::Configuration::DEFAULT_LOGGER
|
|
15
|
-
end
|
|
16
|
-
Ductwork.logger.level = Ductwork.configuration.logger_level
|
|
17
|
-
|
|
18
|
-
Ductwork::Processes::SupervisorRunner.start!
|
|
19
|
-
end
|
|
7
|
+
def self.start!(args)
|
|
8
|
+
new(args).start!
|
|
9
|
+
end
|
|
20
10
|
|
|
21
|
-
|
|
11
|
+
def initialize(args)
|
|
12
|
+
@args = args
|
|
13
|
+
@options = {}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def start!
|
|
17
|
+
option_parser.parse!(args)
|
|
18
|
+
auto_configure
|
|
19
|
+
supervisor_runner.start!
|
|
20
|
+
end
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
options = {}
|
|
22
|
+
private
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
op.banner = "ductwork [options]"
|
|
24
|
+
attr_reader :args, :options
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
def option_parser
|
|
27
|
+
OptionParser.new do |op|
|
|
28
|
+
op.banner = "ductwork [options]"
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
end
|
|
30
|
+
op.on("-c", "--config PATH", "path to YAML config file") do |arg|
|
|
31
|
+
options[:path] = arg
|
|
32
|
+
end
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
end.parse!(args)
|
|
34
|
+
op.on("-h", "--help", "Prints this help") do
|
|
35
|
+
puts op
|
|
36
|
+
exit
|
|
37
|
+
end
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
op.on("-v", "--version", "Prints the version") do
|
|
40
|
+
puts "Ductwork #{Ductwork::VERSION}"
|
|
41
|
+
exit
|
|
42
|
+
end
|
|
45
43
|
end
|
|
46
44
|
end
|
|
45
|
+
|
|
46
|
+
def auto_configure
|
|
47
|
+
Ductwork.configuration = Configuration.new(**options)
|
|
48
|
+
Ductwork.logger = if Ductwork.configuration.logger_source == "rails"
|
|
49
|
+
Rails.logger
|
|
50
|
+
else
|
|
51
|
+
Ductwork::Configuration::DEFAULT_LOGGER
|
|
52
|
+
end
|
|
53
|
+
Ductwork.logger.level = Ductwork.configuration.logger_level
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def supervisor_runner
|
|
57
|
+
Ductwork::Processes::SupervisorRunner
|
|
58
|
+
end
|
|
47
59
|
end
|
|
48
60
|
end
|
|
@@ -16,6 +16,7 @@ module Ductwork
|
|
|
16
16
|
pending: "pending",
|
|
17
17
|
in_progress: "in_progress",
|
|
18
18
|
waiting: "waiting",
|
|
19
|
+
advancing: "advancing",
|
|
19
20
|
halted: "halted",
|
|
20
21
|
completed: "completed"
|
|
21
22
|
|
|
@@ -71,7 +72,7 @@ module Ductwork
|
|
|
71
72
|
step = p.steps.create!(
|
|
72
73
|
klass: step_klass,
|
|
73
74
|
status: :in_progress,
|
|
74
|
-
|
|
75
|
+
to_transition: :start,
|
|
75
76
|
started_at: Time.current
|
|
76
77
|
)
|
|
77
78
|
Ductwork::Job.enqueue(step, args)
|
|
@@ -113,10 +114,15 @@ module Ductwork
|
|
|
113
114
|
|
|
114
115
|
private
|
|
115
116
|
|
|
116
|
-
def create_step_and_enqueue_job(
|
|
117
|
+
def create_step_and_enqueue_job(edge:, input_arg:, klass: nil)
|
|
117
118
|
status = :in_progress
|
|
118
119
|
started_at = Time.current
|
|
119
|
-
|
|
120
|
+
# NOTE: "chain" is used by ActiveRecord so we have to call
|
|
121
|
+
# this enum value "default" :sad:
|
|
122
|
+
to_transition = edge[:type] == "chain" ? "default" : edge[:type]
|
|
123
|
+
klass ||= edge.fetch(:to).sole
|
|
124
|
+
|
|
125
|
+
next_step = steps.create!(klass:, status:, to_transition:, started_at:)
|
|
120
126
|
Ductwork::Job.enqueue(next_step, input_arg)
|
|
121
127
|
end
|
|
122
128
|
|
|
@@ -157,11 +163,8 @@ module Ductwork
|
|
|
157
163
|
else
|
|
158
164
|
edges.each do |step_klass, step_edges|
|
|
159
165
|
edge = step_edges[-1]
|
|
160
|
-
# NOTE: "chain" is used by ActiveRecord so we have to call
|
|
161
|
-
# this enum value "default" :sad:
|
|
162
|
-
step_type = edge[:type] == "chain" ? "default" : edge[:type]
|
|
163
166
|
|
|
164
|
-
if
|
|
167
|
+
if edge[:type] == "collapse"
|
|
165
168
|
conditionally_collapse_next_steps(step_klass, edge, advancing_ids)
|
|
166
169
|
else
|
|
167
170
|
advance_non_merging_steps(step_klass, edge, advancing_ids)
|
|
@@ -172,19 +175,17 @@ module Ductwork
|
|
|
172
175
|
end
|
|
173
176
|
|
|
174
177
|
def advance_non_merging_steps(step_klass, edge, advancing_ids)
|
|
175
|
-
|
|
176
|
-
# this enum value "default" :sad:
|
|
177
|
-
step_type = edge[:type] == "chain" ? "default" : edge[:type]
|
|
178
|
+
to_transition = edge[:type]
|
|
178
179
|
|
|
179
180
|
steps.where(id: advancing_ids, klass: step_klass).find_each do |step|
|
|
180
|
-
if
|
|
181
|
-
advance_to_next_steps(
|
|
182
|
-
elsif
|
|
183
|
-
expand_to_next_steps(
|
|
181
|
+
if to_transition.in?(%w[chain divide])
|
|
182
|
+
advance_to_next_steps(step.id, edge)
|
|
183
|
+
elsif to_transition == "expand"
|
|
184
|
+
expand_to_next_steps(step.id, edge)
|
|
184
185
|
else
|
|
185
186
|
Ductwork.logger.error(
|
|
186
|
-
msg: "Invalid
|
|
187
|
-
|
|
187
|
+
msg: "Invalid To Transition",
|
|
188
|
+
to_transition: to_transition,
|
|
188
189
|
pipeline_id: id,
|
|
189
190
|
role: :pipeline_advancer
|
|
190
191
|
)
|
|
@@ -192,7 +193,7 @@ module Ductwork
|
|
|
192
193
|
end
|
|
193
194
|
end
|
|
194
195
|
|
|
195
|
-
def advance_to_next_steps(
|
|
196
|
+
def advance_to_next_steps(step_id, edge)
|
|
196
197
|
too_many = edge[:to].tally.any? do |to_klass, count|
|
|
197
198
|
depth = Ductwork
|
|
198
199
|
.configuration
|
|
@@ -204,15 +205,9 @@ module Ductwork
|
|
|
204
205
|
if too_many
|
|
205
206
|
halted!
|
|
206
207
|
else
|
|
207
|
-
edge[:to].each do |
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
status: :in_progress,
|
|
211
|
-
step_type: step_type,
|
|
212
|
-
started_at: Time.current
|
|
213
|
-
)
|
|
214
|
-
return_value = Ductwork::Job.find_by(step_id:).return_value
|
|
215
|
-
Ductwork::Job.enqueue(next_step, return_value)
|
|
208
|
+
edge[:to].each do |klass|
|
|
209
|
+
input_arg = Ductwork::Job.find_by(step_id:).return_value
|
|
210
|
+
create_step_and_enqueue_job(edge:, input_arg:, klass:)
|
|
216
211
|
end
|
|
217
212
|
end
|
|
218
213
|
end
|
|
@@ -230,8 +225,7 @@ module Ductwork
|
|
|
230
225
|
end
|
|
231
226
|
|
|
232
227
|
def combine_next_steps(edges, advancing_ids)
|
|
233
|
-
|
|
234
|
-
step_type = "combine"
|
|
228
|
+
edge = edges.values.sample[-1]
|
|
235
229
|
groups = steps
|
|
236
230
|
.where(id: advancing_ids)
|
|
237
231
|
.group(:klass)
|
|
@@ -243,11 +237,11 @@ module Ductwork
|
|
|
243
237
|
input_arg = Ductwork::Job
|
|
244
238
|
.where(step_id: group.map(&:id))
|
|
245
239
|
.map(&:return_value)
|
|
246
|
-
create_step_and_enqueue_job(
|
|
240
|
+
create_step_and_enqueue_job(edge:, input_arg:)
|
|
247
241
|
end
|
|
248
242
|
end
|
|
249
243
|
|
|
250
|
-
def expand_to_next_steps(
|
|
244
|
+
def expand_to_next_steps(step_id, edge)
|
|
251
245
|
next_klass = edge[:to].sole
|
|
252
246
|
return_value = Ductwork::Job
|
|
253
247
|
.find_by(step_id:)
|
|
@@ -258,18 +252,14 @@ module Ductwork
|
|
|
258
252
|
halted!
|
|
259
253
|
else
|
|
260
254
|
Array(return_value).each do |input_arg|
|
|
261
|
-
create_step_and_enqueue_job(
|
|
262
|
-
klass: next_klass,
|
|
263
|
-
step_type: step_type,
|
|
264
|
-
input_arg: input_arg
|
|
265
|
-
)
|
|
255
|
+
create_step_and_enqueue_job(edge:, input_arg:)
|
|
266
256
|
end
|
|
267
257
|
end
|
|
268
258
|
end
|
|
269
259
|
|
|
270
260
|
def conditionally_collapse_next_steps(step_klass, edge, advancing_ids)
|
|
271
261
|
if steps.where(status: %w[pending in_progress], klass: step_klass).none?
|
|
272
|
-
collapse_next_steps(edge
|
|
262
|
+
collapse_next_steps(edge, advancing_ids)
|
|
273
263
|
else
|
|
274
264
|
Ductwork.logger.debug(
|
|
275
265
|
msg: "Not all expanded steps have completed; not collapsing",
|
|
@@ -279,15 +269,14 @@ module Ductwork
|
|
|
279
269
|
end
|
|
280
270
|
end
|
|
281
271
|
|
|
282
|
-
def collapse_next_steps(
|
|
283
|
-
step_type = "collapse"
|
|
272
|
+
def collapse_next_steps(edge, advancing_ids)
|
|
284
273
|
input_arg = []
|
|
285
274
|
|
|
286
275
|
Ductwork::Job.where(step_id: advancing_ids).find_each do |job|
|
|
287
276
|
input_arg << job.return_value
|
|
288
277
|
end
|
|
289
278
|
|
|
290
|
-
create_step_and_enqueue_job(
|
|
279
|
+
create_step_and_enqueue_job(edge:, input_arg:)
|
|
291
280
|
end
|
|
292
281
|
|
|
293
282
|
def log_pipeline_advanced(edges)
|
data/lib/ductwork/models/step.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Ductwork
|
|
|
7
7
|
|
|
8
8
|
validates :klass, presence: true
|
|
9
9
|
validates :status, presence: true
|
|
10
|
-
validates :
|
|
10
|
+
validates :to_transition, presence: true
|
|
11
11
|
|
|
12
12
|
enum :status,
|
|
13
13
|
pending: "pending",
|
|
@@ -17,7 +17,7 @@ module Ductwork
|
|
|
17
17
|
failed: "failed",
|
|
18
18
|
completed: "completed"
|
|
19
19
|
|
|
20
|
-
enum :
|
|
20
|
+
enum :to_transition,
|
|
21
21
|
start: "start",
|
|
22
22
|
default: "default", # `chain` is used by AR
|
|
23
23
|
divide: "divide",
|
|
@@ -26,7 +26,10 @@ module Ductwork
|
|
|
26
26
|
if id.present?
|
|
27
27
|
rows_updated = Ductwork::Pipeline
|
|
28
28
|
.where(id: id, claimed_for_advancing_at: nil)
|
|
29
|
-
.update_all(
|
|
29
|
+
.update_all(
|
|
30
|
+
claimed_for_advancing_at: Time.current,
|
|
31
|
+
status: "advancing"
|
|
32
|
+
)
|
|
30
33
|
|
|
31
34
|
if rows_updated == 1
|
|
32
35
|
Ductwork.logger.debug(
|
|
@@ -50,7 +53,8 @@ module Ductwork
|
|
|
50
53
|
# we're not using a queue so we have to use a db timestamp
|
|
51
54
|
pipeline.update!(
|
|
52
55
|
claimed_for_advancing_at: nil,
|
|
53
|
-
last_advanced_at: Time.current
|
|
56
|
+
last_advanced_at: Time.current,
|
|
57
|
+
status: "in_progress"
|
|
54
58
|
)
|
|
55
59
|
else
|
|
56
60
|
Ductwork.logger.debug(
|
data/lib/ductwork/version.rb
CHANGED
|
@@ -5,10 +5,12 @@ class CreateDuctworkSteps < ActiveRecord::Migration[<%= Rails::VERSION::MAJOR %>
|
|
|
5
5
|
create_table :ductwork_steps do |table|
|
|
6
6
|
table.belongs_to :pipeline, index: true, null: false, foreign_key: { to_table: :ductwork_pipelines }
|
|
7
7
|
table.string :klass, null: false
|
|
8
|
-
table.string :
|
|
8
|
+
table.string :to_transition, null: false
|
|
9
9
|
table.timestamp :started_at
|
|
10
10
|
table.timestamp :completed_at
|
|
11
11
|
table.string :status, null: false
|
|
12
|
+
table.integer :delay_seconds
|
|
13
|
+
table.integer :timeout_seconds
|
|
12
14
|
table.timestamps null: false
|
|
13
15
|
end
|
|
14
16
|
|