good_pipeline 0.5.0 → 0.6.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 +7 -0
- data/README.md +3 -3
- data/demo/test/good_pipeline/test_dashboard.rb +4 -3
- data/demo/test/integration/test_pipeline_chaining.rb +67 -2
- data/docs/failure-strategies.md +5 -1
- data/docs/introduction.md +1 -1
- data/docs/monitoring.md +1 -1
- data/docs/pipeline-chaining.md +10 -6
- data/gemfiles/rails_7_2.gemfile.lock +2 -2
- data/gemfiles/rails_8_0.gemfile.lock +2 -2
- data/gemfiles/rails_8_1.gemfile.lock +2 -2
- data/lib/good_pipeline/chain_coordinator.rb +8 -4
- data/lib/good_pipeline/version.rb +1 -1
- data/mise.toml +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4294d8f713a4aa48f6d9680f1b3d1c264f9ff51ec5fb0f38c1347bf3f7f44e19
|
|
4
|
+
data.tar.gz: 428d2ba77ef93e773b6016c3220eeb76174fcdea9463f71e3b150766e66f15e8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: df4a09f4fe2b67119f633e10ef83a05f24315b0017b8b634acfca6a9efc18182b9c6419cab8e0b1cdd0587be694e1c84c779b85c4875b5aef4ee13e4eedc3388
|
|
7
|
+
data.tar.gz: 975e92dfb856c37fa1806951798fbb449b4c1e6bec3df3bb241c1621c1bf3f88b81e61c3c039c3f0a64ea6620c084048b5a8ba5afb959921edadf9c533210745
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.6.0] - 2026-10-29
|
|
4
|
+
|
|
5
|
+
### Breaking changes
|
|
6
|
+
|
|
7
|
+
- **Chain failure strategies** — chained pipelines now use each upstream pipeline's stored `failure_strategy`. An upstream that succeeds or fails with `:ignore` satisfies its chain dependency; any other terminal outcome skips dependents. Downstream pipelines wait for every dependency, including when chains are registered after an upstream finishes. Ignored failures keep their `failed` status and failure callbacks. No new setting or migration is required.
|
|
8
|
+
- **Ruby 4 minimum** — GoodPipeline now requires Ruby 4.0 or newer. Development, CI, and gem releases use Ruby 4.0.9.
|
|
9
|
+
|
|
3
10
|
## [0.5.0] - 2026-09-01
|
|
4
11
|
|
|
5
12
|
### Added
|
data/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Define multi-step workflows as directed acyclic graphs — not linear chains. St
|
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
9
|
-
- Ruby >=
|
|
9
|
+
- Ruby >= 4.0
|
|
10
10
|
- Rails >= 7.2
|
|
11
11
|
- PostgreSQL
|
|
12
12
|
- GoodJob >= 4.14 with `preserve_job_records = true`
|
|
@@ -126,7 +126,7 @@ Set at the pipeline level with `failure_strategy`:
|
|
|
126
126
|
|---|---|
|
|
127
127
|
| `:halt` (default) | Stop all pending steps when any step fails |
|
|
128
128
|
| `:continue` | Let independent branches continue; skip only blocked downstream steps |
|
|
129
|
-
| `:ignore` | Treat
|
|
129
|
+
| `:ignore` | Treat failed steps and pipelines as satisfied for dependency resolution |
|
|
130
130
|
|
|
131
131
|
Per-step overrides via `on_failure:` in `run` apply to that step's outgoing edges only.
|
|
132
132
|
|
|
@@ -201,7 +201,7 @@ GoodPipeline.run(
|
|
|
201
201
|
).then(MergeMediaPipeline, with: { video_id: 123, audio_id: 456 })
|
|
202
202
|
```
|
|
203
203
|
|
|
204
|
-
|
|
204
|
+
Chained pipelines wait for every upstream to succeed or fail with `failure_strategy :ignore`. Any other terminal outcome skips dependent pipelines. Ignored failures keep their `failed` status and still trigger failure callbacks.
|
|
205
205
|
|
|
206
206
|
### Monitoring
|
|
207
207
|
|
|
@@ -32,15 +32,16 @@ module GoodPipeline
|
|
|
32
32
|
assert_select ".gp-status-filter-scroll > .gp-segment[role=group][aria-label='Status filter']", count: 1
|
|
33
33
|
assert_includes response.body, %(id="gp-table")
|
|
34
34
|
assert_no_match(/data-href/, response.body)
|
|
35
|
-
|
|
35
|
+
asset_version = GoodPipeline::VERSION.tr(".", "-")
|
|
36
|
+
asset_href = response.body[%r{href="([^"]*/frontend/static/#{asset_version}/dashboard\.css)"}, 1]
|
|
36
37
|
|
|
37
|
-
assert asset_href&.end_with?("/frontend/static/
|
|
38
|
+
assert asset_href&.end_with?("/frontend/static/#{asset_version}/dashboard.css")
|
|
38
39
|
refute_includes response.body, "style.css"
|
|
39
40
|
refute_includes response.body, "<script>"
|
|
40
41
|
|
|
41
42
|
assert_dashboard_css(asset_href)
|
|
42
43
|
|
|
43
|
-
get "/good_pipeline/frontend/static/
|
|
44
|
+
get "/good_pipeline/frontend/static/#{asset_version}/dashboard.js"
|
|
44
45
|
|
|
45
46
|
assert_response :success
|
|
46
47
|
assert_includes response.media_type, "javascript"
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require "test_helper"
|
|
4
4
|
|
|
5
|
+
class IgnoreChainPipeline < ContinueTestPipeline
|
|
6
|
+
failure_strategy :ignore
|
|
7
|
+
end
|
|
8
|
+
|
|
5
9
|
class TestPipelineChaining < ActiveSupport::TestCase
|
|
6
10
|
def run_all_to_completion(pipeline_records, timeout: 15)
|
|
7
11
|
deadline = Time.current + timeout
|
|
@@ -46,6 +50,32 @@ class TestPipelineChaining < ActiveSupport::TestCase
|
|
|
46
50
|
assert_equal "skipped", downstream.status
|
|
47
51
|
end
|
|
48
52
|
|
|
53
|
+
def test_ignored_failure_stays_failed_and_allows_the_chain_to_finish
|
|
54
|
+
IgnoreChainPipeline.run
|
|
55
|
+
.then(NotificationPipeline, with: {})
|
|
56
|
+
.then(ArchivePipeline, with: {})
|
|
57
|
+
|
|
58
|
+
run_all_to_completion(GoodPipeline::PipelineRecord.all.to_a)
|
|
59
|
+
|
|
60
|
+
assert_equal(
|
|
61
|
+
{ "IgnoreChainPipeline" => "failed", "NotificationPipeline" => "succeeded", "ArchivePipeline" => "succeeded" },
|
|
62
|
+
GoodPipeline::PipelineRecord.pluck(:type, :status).to_h
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_continue_failure_skips_dependents_even_when_they_use_ignore
|
|
67
|
+
ContinueTestPipeline.run
|
|
68
|
+
.then(IgnoreChainPipeline, with: {})
|
|
69
|
+
.then(NotificationPipeline, with: {})
|
|
70
|
+
|
|
71
|
+
run_all_to_completion(GoodPipeline::PipelineRecord.all.to_a)
|
|
72
|
+
|
|
73
|
+
assert_equal(
|
|
74
|
+
{ "ContinueTestPipeline" => "failed", "IgnoreChainPipeline" => "skipped", "NotificationPipeline" => "skipped" },
|
|
75
|
+
GoodPipeline::PipelineRecord.pluck(:type, :status).to_h
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
49
79
|
# --- Fan-out ---
|
|
50
80
|
|
|
51
81
|
def test_fan_out_both_start_after_upstream_succeeds
|
|
@@ -118,6 +148,41 @@ class TestPipelineChaining < ActiveSupport::TestCase
|
|
|
118
148
|
assert_equal "skipped", archive.status
|
|
119
149
|
end
|
|
120
150
|
|
|
151
|
+
def test_ignored_failure_waits_for_the_other_upstream_to_finish
|
|
152
|
+
ignored = create_pipeline(status: "running", on_failure_strategy: "ignore")
|
|
153
|
+
ignored_step = build_step(ignored, key: "optional", coordination_status: "enqueued")
|
|
154
|
+
waiting = create_pipeline(status: "running", on_failure_strategy: "halt")
|
|
155
|
+
waiting_step = build_step(waiting, key: "required", coordination_status: "enqueued")
|
|
156
|
+
downstream = GoodPipeline::Chain.new([ignored, waiting]).then(NotificationPipeline)
|
|
157
|
+
|
|
158
|
+
GoodPipeline::Coordinator.complete_step(ignored_step.id, succeeded: false)
|
|
159
|
+
|
|
160
|
+
assert_equal "pending", downstream.reload.status
|
|
161
|
+
|
|
162
|
+
GoodPipeline::Coordinator.complete_step(waiting_step.id, succeeded: true)
|
|
163
|
+
|
|
164
|
+
assert_equal "running", downstream.reload.status
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def test_fan_in_requires_every_failure_to_be_ignored
|
|
168
|
+
ignored = create_pipeline(status: "failed", on_failure_strategy: "ignore")
|
|
169
|
+
blocking = create_pipeline(status: "failed", on_failure_strategy: "continue")
|
|
170
|
+
|
|
171
|
+
downstream = GoodPipeline::Chain.new([ignored, blocking]).then(NotificationPipeline)
|
|
172
|
+
|
|
173
|
+
assert_equal "skipped", downstream.reload.status
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def test_late_chain_registration_accepts_an_ignored_failure
|
|
177
|
+
upstream = IgnoreChainPipeline.run
|
|
178
|
+
run_pipeline_to_completion(upstream)
|
|
179
|
+
|
|
180
|
+
downstream = upstream.then(NotificationPipeline)
|
|
181
|
+
run_pipeline_to_completion(downstream)
|
|
182
|
+
|
|
183
|
+
assert_equal "succeeded", downstream.reload.status
|
|
184
|
+
end
|
|
185
|
+
|
|
121
186
|
# --- Fan-out then fan-in ---
|
|
122
187
|
|
|
123
188
|
def test_fan_out_then_fan_in
|
|
@@ -159,7 +224,7 @@ class TestPipelineChaining < ActiveSupport::TestCase
|
|
|
159
224
|
end
|
|
160
225
|
|
|
161
226
|
def test_canceling_pending_upstream_automatically_skips_downstream
|
|
162
|
-
upstream = create_pipeline(type: "TestPipeline", status: "pending", on_failure_strategy: "
|
|
227
|
+
upstream = create_pipeline(type: "TestPipeline", status: "pending", on_failure_strategy: "ignore")
|
|
163
228
|
upstream_step = build_step(upstream, key: "work")
|
|
164
229
|
downstream = create_pipeline(type: "NotificationPipeline", status: "pending", on_failure_strategy: "halt")
|
|
165
230
|
GoodPipeline::ChainRecord.create!(upstream_pipeline: upstream, downstream_pipeline: downstream)
|
|
@@ -172,7 +237,7 @@ class TestPipelineChaining < ActiveSupport::TestCase
|
|
|
172
237
|
end
|
|
173
238
|
|
|
174
239
|
def test_canceling_running_upstream_waits_for_drain_before_skipping_downstream
|
|
175
|
-
upstream = create_pipeline(type: "TestPipeline", status: "running", on_failure_strategy: "
|
|
240
|
+
upstream = create_pipeline(type: "TestPipeline", status: "running", on_failure_strategy: "ignore")
|
|
176
241
|
upstream_step = build_step(upstream, key: "work")
|
|
177
242
|
upstream_step.update_columns(coordination_status: "enqueued")
|
|
178
243
|
downstream = create_pipeline(type: "NotificationPipeline", status: "pending", on_failure_strategy: "halt")
|
data/docs/failure-strategies.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Failure Strategies
|
|
2
2
|
|
|
3
|
-
Three failure strategies control what happens when a step fails. Set one at the pipeline level, then override per step if needed.
|
|
3
|
+
Three failure strategies control what happens when a step fails and whether a failed pipeline allows its chain to continue. Set one at the pipeline level, then override per step if needed.
|
|
4
4
|
|
|
5
5
|
## Pipeline-level strategy
|
|
6
6
|
|
|
@@ -140,6 +140,10 @@ A barrier depends on every step in its preceding phase, so the same rules apply
|
|
|
140
140
|
|
|
141
141
|
Whenever eligible work remains, every new terminal step releases its outgoing dependency counter exactly once. This includes enqueue-time configuration failures and steps skipped by partial halt propagation, preventing a barrier or ordinary fan-in from remaining pending after all upstreams are terminal.
|
|
142
142
|
|
|
143
|
+
## Pipeline chains
|
|
144
|
+
|
|
145
|
+
Pipeline chains use each upstream pipeline's stored `failure_strategy`. Step-level overrides do not change the chain policy. See [Pipeline Chaining](./pipeline-chaining.md#unsuccessful-upstream-propagation) for how failures affect dependent pipelines.
|
|
146
|
+
|
|
143
147
|
## Early termination with success
|
|
144
148
|
|
|
145
149
|
Sometimes a job determines there is nothing to do — the account is deactivated, the resource was already processed, etc. Call `halt_pipeline!` to stop the pipeline early and mark it as `succeeded`:
|
data/docs/introduction.md
CHANGED
data/docs/monitoring.md
CHANGED
|
@@ -45,7 +45,7 @@ step.duration # => 12.34 (Float seconds, from GoodJob record)
|
|
|
45
45
|
| `succeeded` | All steps terminal, none failed |
|
|
46
46
|
| `failed` | One or more steps failed; `:continue` or `:ignore` strategy was used |
|
|
47
47
|
| `halted` | `:halt` strategy was applied — `halt_triggered` is `true` |
|
|
48
|
-
| `skipped` |
|
|
48
|
+
| `skipped` | An upstream pipeline failed without `:ignore`, halted, was canceled, or was skipped |
|
|
49
49
|
| `canceled` | Cancellation completed, or a pending pipeline was canceled before it started — terminal |
|
|
50
50
|
|
|
51
51
|
## Step statuses
|
data/docs/pipeline-chaining.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Pipeline Chaining
|
|
2
2
|
|
|
3
|
-
Pipelines can be wired together into pipeline-level DAGs. A downstream pipeline starts
|
|
3
|
+
Pipelines can be wired together into pipeline-level DAGs. A downstream pipeline starts after every upstream has succeeded or failed with `failure_strategy :ignore`.
|
|
4
|
+
|
|
5
|
+
The examples below use the default `:halt` strategy unless another strategy is shown.
|
|
4
6
|
|
|
5
7
|
## Serial chain
|
|
6
8
|
|
|
@@ -88,9 +90,9 @@ Pipeline chaining is a first-class primitive — upstream/downstream relationshi
|
|
|
88
90
|
1. Creates downstream pipeline records with `status: pending` — params are stored immediately at chain registration time
|
|
89
91
|
2. Creates `good_pipeline_chains` rows linking upstream to downstream pipeline IDs
|
|
90
92
|
3. If any upstream has already reached a terminal state, immediately triggers chain propagation so the downstream is started or skipped
|
|
91
|
-
4. After any upstream pipeline reaches a terminal state, the chain coordinator checks
|
|
92
|
-
5. If
|
|
93
|
-
6. If any upstream
|
|
93
|
+
4. After any upstream pipeline reaches a terminal state, the chain coordinator checks each upstream's status and stored failure strategy
|
|
94
|
+
5. If every upstream succeeded or failed with `:ignore`, the downstream pipeline starts (root steps are enqueued)
|
|
95
|
+
6. If any terminal upstream does not satisfy its dependency, the downstream pipeline is set to `skipped`
|
|
94
96
|
|
|
95
97
|
The chain coordinator uses a blocking `FOR UPDATE` row lock. A contending propagation waits, then rechecks the downstream pipeline while locked, so a fan-in wake-up cannot be silently dropped. This also makes `.then` safe to call after an upstream has already completed.
|
|
96
98
|
|
|
@@ -98,14 +100,16 @@ Individual chain transitions are atomic and propagation is idempotent, but deliv
|
|
|
98
100
|
|
|
99
101
|
## Unsuccessful upstream propagation
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
A failed upstream using `failure_strategy :ignore` allows the chain to continue after it finishes. Its status remains `failed`, and failure callbacks still run. The pipeline-level strategy controls chain dependencies; a step-level `on_failure:` override only controls that step's outgoing edges inside its pipeline.
|
|
104
|
+
|
|
105
|
+
If any upstream pipeline fails with `:continue`, halts, is canceled, or is skipped:
|
|
102
106
|
|
|
103
107
|
- The downstream pipeline transitions to `skipped`
|
|
104
108
|
- Any further downstream pipelines are also recursively `skipped`
|
|
105
109
|
- `on_complete` callbacks fire on skipped pipelines, but `on_failure` does **not** — being skipped is not considered a failure
|
|
106
110
|
|
|
107
111
|
```
|
|
108
|
-
A (failed) → B (skipped) → C (skipped) → D (skipped)
|
|
112
|
+
A (failed, :continue) → B (skipped) → C (skipped) → D (skipped)
|
|
109
113
|
```
|
|
110
114
|
|
|
111
115
|
A `canceling` upstream is still nonterminal, so its downstream pipelines remain pending while already-enqueued work drains. Once the upstream reaches `canceled`, normal chain propagation skips the pending downstream graph.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
good_pipeline (0.
|
|
4
|
+
good_pipeline (0.6.0)
|
|
5
5
|
activerecord (>= 7.2)
|
|
6
6
|
good_job (>= 4.14)
|
|
7
7
|
railties (>= 7.2)
|
|
@@ -336,7 +336,7 @@ CHECKSUMS
|
|
|
336
336
|
fugit (1.13.0) sha256=a4f093fce740da52f216740a5041e2a594ea763cdb89e8b2754ca4399634ab18
|
|
337
337
|
globalid (1.4.0) sha256=037f12fbf1d9d7a014d501c2d5c77356fd4ddd96d7a7991d6700bba96706f427
|
|
338
338
|
good_job (4.19.2) sha256=73f4ea0595a29d28b9d9c0bf23361cc7434542b4d286f59b803819110c26e4b0
|
|
339
|
-
good_pipeline (0.
|
|
339
|
+
good_pipeline (0.6.0)
|
|
340
340
|
i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5
|
|
341
341
|
io-console (0.9.2) sha256=efa74f891dd03c0939a931dfc6e74c2813d904763d456ea9762b0525e748db08
|
|
342
342
|
irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
good_pipeline (0.
|
|
4
|
+
good_pipeline (0.6.0)
|
|
5
5
|
activerecord (>= 7.2)
|
|
6
6
|
good_job (>= 4.14)
|
|
7
7
|
railties (>= 7.2)
|
|
@@ -334,7 +334,7 @@ CHECKSUMS
|
|
|
334
334
|
fugit (1.13.0) sha256=a4f093fce740da52f216740a5041e2a594ea763cdb89e8b2754ca4399634ab18
|
|
335
335
|
globalid (1.4.0) sha256=037f12fbf1d9d7a014d501c2d5c77356fd4ddd96d7a7991d6700bba96706f427
|
|
336
336
|
good_job (4.19.2) sha256=73f4ea0595a29d28b9d9c0bf23361cc7434542b4d286f59b803819110c26e4b0
|
|
337
|
-
good_pipeline (0.
|
|
337
|
+
good_pipeline (0.6.0)
|
|
338
338
|
i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5
|
|
339
339
|
io-console (0.9.2) sha256=efa74f891dd03c0939a931dfc6e74c2813d904763d456ea9762b0525e748db08
|
|
340
340
|
irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
good_pipeline (0.
|
|
4
|
+
good_pipeline (0.6.0)
|
|
5
5
|
activerecord (>= 7.2)
|
|
6
6
|
good_job (>= 4.14)
|
|
7
7
|
railties (>= 7.2)
|
|
@@ -338,7 +338,7 @@ CHECKSUMS
|
|
|
338
338
|
fugit (1.13.0) sha256=a4f093fce740da52f216740a5041e2a594ea763cdb89e8b2754ca4399634ab18
|
|
339
339
|
globalid (1.4.0) sha256=037f12fbf1d9d7a014d501c2d5c77356fd4ddd96d7a7991d6700bba96706f427
|
|
340
340
|
good_job (4.19.2) sha256=73f4ea0595a29d28b9d9c0bf23361cc7434542b4d286f59b803819110c26e4b0
|
|
341
|
-
good_pipeline (0.
|
|
341
|
+
good_pipeline (0.6.0)
|
|
342
342
|
i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5
|
|
343
343
|
io-console (0.9.2) sha256=efa74f891dd03c0939a931dfc6e74c2813d904763d456ea9762b0525e748db08
|
|
344
344
|
irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
|
|
@@ -22,7 +22,7 @@ module GoodPipeline
|
|
|
22
22
|
locked.transition_to!(:skipped)
|
|
23
23
|
Coordinator.dispatch_callbacks_once(locked, :skipped)
|
|
24
24
|
skipped_downstream_ids = locked.downstream_pipelines.pluck(:id)
|
|
25
|
-
elsif
|
|
25
|
+
elsif all_upstreams_satisfied?(locked)
|
|
26
26
|
start_pipeline(locked)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -32,12 +32,16 @@ module GoodPipeline
|
|
|
32
32
|
|
|
33
33
|
def should_skip_downstream?(pipeline)
|
|
34
34
|
pipeline.upstream_pipelines.any? do |upstream|
|
|
35
|
-
upstream.
|
|
35
|
+
upstream.terminal? && !upstream_satisfied?(upstream)
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def
|
|
40
|
-
|
|
39
|
+
def upstream_satisfied?(upstream)
|
|
40
|
+
upstream.succeeded? || (upstream.failed? && upstream.ignore?)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def all_upstreams_satisfied?(pipeline)
|
|
44
|
+
pipeline.upstream_pipelines.all? { |upstream| upstream_satisfied?(upstream) }
|
|
41
45
|
end
|
|
42
46
|
|
|
43
47
|
def start_pipeline(pipeline_record)
|
data/mise.toml
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: good_pipeline
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ali Hamdi Ali Fadel
|
|
@@ -248,14 +248,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
248
248
|
requirements:
|
|
249
249
|
- - ">="
|
|
250
250
|
- !ruby/object:Gem::Version
|
|
251
|
-
version:
|
|
251
|
+
version: 4.0.0
|
|
252
252
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
253
253
|
requirements:
|
|
254
254
|
- - ">="
|
|
255
255
|
- !ruby/object:Gem::Version
|
|
256
256
|
version: '0'
|
|
257
257
|
requirements: []
|
|
258
|
-
rubygems_version:
|
|
258
|
+
rubygems_version: 4.0.20
|
|
259
259
|
specification_version: 4
|
|
260
260
|
summary: DAG-based job pipeline orchestration for Rails, built on GoodJob
|
|
261
261
|
test_files: []
|