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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6174d886b38c9a000eda9937e27efabd0f89a803c5c77fb5739c2b67d8c004c9
4
- data.tar.gz: 6300c6f3d238e2f92aa74c5ebe01c37bcbf842693f186b9c56e8d8b2cbcf567d
3
+ metadata.gz: f64abfa6d358cd7b225baae1b801894032936bef4de86ff0843e3163552aa530
4
+ data.tar.gz: aedd9daa71379091503375926ea4863a7834193a1701ee265a9b0b99a7fbfe50
5
5
  SHA512:
6
- metadata.gz: fcda67f0378eb7e4108820ce87ac4b508698abcd02e71ef77b7ec8442dfeeea019a77e35bacba5a32fda4101004d2c0f349441d3921838deee97aea6ac93eed5
7
- data.tar.gz: e74fef5cf5bbf80b8b112616636a556a6ec7742ade2fe44dae3679b3c679ef7b9eb96dc81ad016fb1d4285a06cef874f74d1f6c67a20062b5eaa0bdcfde6061c
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
- class << self
8
- def start!(args)
9
- options = parse_options(args)
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
- private
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
- def parse_options(args)
24
- options = {}
22
+ private
25
23
 
26
- OptionParser.new do |op|
27
- op.banner = "ductwork [options]"
24
+ attr_reader :args, :options
28
25
 
29
- op.on("-c", "--config PATH", "path to YAML config file") do |arg|
30
- options[:path] = arg
31
- end
26
+ def option_parser
27
+ OptionParser.new do |op|
28
+ op.banner = "ductwork [options]"
32
29
 
33
- op.on("-h", "--help", "Prints this help") do
34
- puts op
35
- exit
36
- end
30
+ op.on("-c", "--config PATH", "path to YAML config file") do |arg|
31
+ options[:path] = arg
32
+ end
37
33
 
38
- op.on("-v", "--version", "Prints the version") do
39
- puts "Ductwork #{Ductwork::VERSION}"
40
- exit
41
- end
42
- end.parse!(args)
34
+ op.on("-h", "--help", "Prints this help") do
35
+ puts op
36
+ exit
37
+ end
43
38
 
44
- options
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
- step_type: :start,
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(klass:, step_type:, input_arg:)
117
+ def create_step_and_enqueue_job(edge:, input_arg:, klass: nil)
117
118
  status = :in_progress
118
119
  started_at = Time.current
119
- next_step = steps.create!(klass:, status:, step_type:, started_at:)
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 step_type == "collapse"
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
- # NOTE: "chain" is used by ActiveRecord so we have to call
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 step_type.in?(%w[default divide])
181
- advance_to_next_steps(step_type, step.id, edge)
182
- elsif step_type == "expand"
183
- expand_to_next_steps(step_type, step.id, edge)
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 step type",
187
- step_type: step_type,
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(step_type, step_id, edge)
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 |to_klass|
208
- next_step = steps.create!(
209
- klass: to_klass,
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
- klass = edges.values.sample.dig(-1, :to).sole
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(klass:, step_type:, input_arg:)
240
+ create_step_and_enqueue_job(edge:, input_arg:)
247
241
  end
248
242
  end
249
243
 
250
- def expand_to_next_steps(step_type, step_id, edge)
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[:to].sole, advancing_ids)
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(klass, advancing_ids)
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(klass:, step_type:, input_arg:)
279
+ create_step_and_enqueue_job(edge:, input_arg:)
291
280
  end
292
281
 
293
282
  def log_pipeline_advanced(edges)
@@ -7,7 +7,7 @@ module Ductwork
7
7
 
8
8
  validates :klass, presence: true
9
9
  validates :status, presence: true
10
- validates :step_type, presence: true
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 :step_type,
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(claimed_for_advancing_at: Time.current)
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(
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ductwork
4
- VERSION = "0.7.1"
4
+ VERSION = "0.8.0"
5
5
  end
@@ -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 :step_type, null: false
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
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ductwork
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Ewing