job-workflow 0.3.0 → 0.4.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 +11 -0
- data/README.md +1 -1
- data/guides/PRODUCTION_DEPLOYMENT.md +1 -1
- data/guides/README.md +1 -6
- data/lib/job_workflow/context.rb +11 -9
- data/lib/job_workflow/dsl.rb +0 -20
- data/lib/job_workflow/runner.rb +13 -6
- data/lib/job_workflow/task.rb +3 -7
- data/lib/job_workflow/version.rb +1 -1
- data/lib/job_workflow/workflow.rb +0 -11
- data/lib/job_workflow.rb +0 -1
- data/rbs_collection.lock.yaml +11 -11
- data/sig/generated/job_workflow/context.rbs +6 -6
- data/sig/generated/job_workflow/dsl.rbs +0 -8
- data/sig/generated/job_workflow/runner.rbs +5 -2
- data/sig/generated/job_workflow/task.rbs +2 -5
- data/sig/generated/job_workflow/workflow.rbs +0 -5
- metadata +1 -4
- data/guides/NAMESPACES.md +0 -75
- data/lib/job_workflow/namespace.rb +0 -36
- data/sig/generated/job_workflow/namespace.rbs +0 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 213a0654cb0482f1a2574f4e55d26c72f5274d24b61b933abd04e9e21f4c19d1
|
|
4
|
+
data.tar.gz: 0f19fce390ff18dcb13d80c8a4c6841dc2e096d4ea7586f0a2d6e2c6a467a45b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 89e0d194c4f14817bd2866b4b07f2efe3eea0ffdbc74ff4b7c1f5474d59fb0a18749d68fc2c724ea690f370d1b335d1e69bf0f006ab9bb1964f74fcfd689232b
|
|
7
|
+
data.tar.gz: 49150a706fb10a4ba79a87397b4cbbfcb4554eba5e974d22d6176799d377f5d9814f20862be996bca253328fc1efa6a10429947cc308f4aa3dd884eaadd378d0
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.4.0] - 2026-05-12
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Fix `enqueue: true` consumer tasks that read `depends_on` outputs by persisting the parent context before `perform_all_later`, so sub-jobs load the latest dependency outputs instead of stale persisted state
|
|
8
|
+
- Fix sequential `each` task resumption to persist continuation cursor progress at the workflow step level, resume from `step.cursor`, and keep the failed iteration retrying from the same `each_index` without skipping previously collected outputs
|
|
9
|
+
|
|
10
|
+
### Removed
|
|
11
|
+
|
|
12
|
+
- Remove the `namespace` DSL and `JobWorkflow::Namespace`, flatten task naming to a single task space, and delete the dedicated namespace guide/example coverage that existed for the removed feature
|
|
13
|
+
|
|
3
14
|
## [0.3.0] - 2026-03-13
|
|
4
15
|
|
|
5
16
|
### Added
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# JobWorkflow
|
|
2
2
|
|
|
3
|
-
> ⚠️ **Early Stage (v0.
|
|
3
|
+
> ⚠️ **Early Stage (v0.4.0):** This library is in active development. APIs and features may change in breaking ways without notice. Use in production at your own risk and expect potential breaking changes in future releases.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Production Deployment
|
|
2
2
|
|
|
3
|
-
> ⚠️ **Early Stage (v0.
|
|
3
|
+
> ⚠️ **Early Stage (v0.4.0):** JobWorkflow is still in early development. While this section outlines potential deployment patterns, please thoroughly test in your specific environment and monitor for any issues before relying on JobWorkflow in critical production systems.
|
|
4
4
|
|
|
5
5
|
This section covers suggested settings and patterns for running JobWorkflow in production-like environments.
|
|
6
6
|
|
data/guides/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# JobWorkflow Guides
|
|
2
2
|
|
|
3
|
-
> ⚠️ **Early Stage (v0.
|
|
3
|
+
> ⚠️ **Early Stage (v0.4.0):** JobWorkflow is in active development. APIs and features may change. The following guides provide patterns and examples for building workflows, but be aware that implementations may need adjustment as the library evolves.
|
|
4
4
|
|
|
5
5
|
Welcome to the JobWorkflow documentation! This directory contains comprehensive guides to help you build robust workflows with JobWorkflow.
|
|
6
6
|
|
|
@@ -67,11 +67,6 @@ Power features for complex workflows:
|
|
|
67
67
|
- Configuration options (poll_timeout, poll_interval, reschedule_delay)
|
|
68
68
|
- SolidQueue integration
|
|
69
69
|
|
|
70
|
-
- **[NAMESPACES.md](NAMESPACES.md)** - Organizing large workflows
|
|
71
|
-
- Basic namespace usage
|
|
72
|
-
- Nested namespaces
|
|
73
|
-
- Cross-namespace dependencies
|
|
74
|
-
|
|
75
70
|
- **[THROTTLING.md](THROTTLING.md)** - Rate limiting and resource control
|
|
76
71
|
- Task-level throttling
|
|
77
72
|
- Runtime throttling
|
data/lib/job_workflow/context.rb
CHANGED
|
@@ -108,13 +108,13 @@ module JobWorkflow
|
|
|
108
108
|
[task_context.parent_job_id, task.task_name].compact.join("/")
|
|
109
109
|
end
|
|
110
110
|
|
|
111
|
-
#: (Task) -> Enumerator[Context]
|
|
112
|
-
def _with_each_value(task)
|
|
111
|
+
#: (Task, ?start_index: Integer?) -> Enumerator[Context]
|
|
112
|
+
def _with_each_value(task, start_index: nil)
|
|
113
113
|
raise "Nested _with_each_value calls are not allowed" if enabled_with_each_value
|
|
114
114
|
|
|
115
115
|
self.enabled_with_each_value = true
|
|
116
116
|
Enumerator.new do |y|
|
|
117
|
-
with_task_context(task, y)
|
|
117
|
+
with_task_context(task, y, start_index:)
|
|
118
118
|
ensure
|
|
119
119
|
self.enabled_with_each_value = false
|
|
120
120
|
end
|
|
@@ -270,11 +270,11 @@ module JobWorkflow
|
|
|
270
270
|
}
|
|
271
271
|
end
|
|
272
272
|
|
|
273
|
-
#: (Task, Enumerator::Yielder) -> void
|
|
274
|
-
def with_task_context(task, yielder) # rubocop:disable Metrics/MethodLength
|
|
273
|
+
#: (Task, Enumerator::Yielder, ?start_index: Integer?) -> void
|
|
274
|
+
def with_task_context(task, yielder, start_index: nil) # rubocop:disable Metrics/MethodLength
|
|
275
275
|
reset_task_context_if_task_changed(task)
|
|
276
276
|
|
|
277
|
-
with_each_index_and_value(task) do |value, index|
|
|
277
|
+
with_each_index_and_value(task, start_index:) do |value, index|
|
|
278
278
|
dry_run = calculate_dry_run(task)
|
|
279
279
|
with_retry(task) do |retry_count|
|
|
280
280
|
self.task_context = TaskContext.new(task:, parent_job_id:, index:, value:, retry_count:, dry_run:)
|
|
@@ -294,10 +294,12 @@ module JobWorkflow
|
|
|
294
294
|
self.task_context = TaskContext.new if task_context.task&.task_name != task.task_name
|
|
295
295
|
end
|
|
296
296
|
|
|
297
|
-
#: (Task) { (untyped, Integer) -> void } -> void
|
|
298
|
-
def with_each_index_and_value(task)
|
|
297
|
+
#: (Task, ?start_index: Integer?) { (untyped, Integer) -> void } -> void
|
|
298
|
+
def with_each_index_and_value(task, start_index: nil)
|
|
299
|
+
resume_index = start_index || task_context.index
|
|
300
|
+
|
|
299
301
|
task.each.call(self).each.with_index do |value, index|
|
|
300
|
-
next if index <
|
|
302
|
+
next if index < resume_index
|
|
301
303
|
|
|
302
304
|
yield value, index
|
|
303
305
|
|
data/lib/job_workflow/dsl.rb
CHANGED
|
@@ -108,15 +108,9 @@ module JobWorkflow
|
|
|
108
108
|
|
|
109
109
|
#: (Symbol argument_name, String type, ?default: untyped) -> void
|
|
110
110
|
def argument(argument_name, type, default: nil)
|
|
111
|
-
validate_namespace!
|
|
112
111
|
_workflow.add_argument(ArgumentDef.new(name: argument_name, type:, default:))
|
|
113
112
|
end
|
|
114
113
|
|
|
115
|
-
#: (Symbol) { () -> void } -> void
|
|
116
|
-
def namespace(namespace_name, &)
|
|
117
|
-
_workflow.add_namespace(Namespace.new(name: namespace_name), &)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
114
|
# rubocop:disable Metrics/ParameterLists
|
|
121
115
|
#
|
|
122
116
|
#: (
|
|
@@ -149,7 +143,6 @@ module JobWorkflow
|
|
|
149
143
|
new_task = Task.new(
|
|
150
144
|
job_name: name,
|
|
151
145
|
name: task_name,
|
|
152
|
-
namespace: _workflow.namespace,
|
|
153
146
|
block: block,
|
|
154
147
|
enqueue:,
|
|
155
148
|
each:,
|
|
@@ -172,25 +165,21 @@ module JobWorkflow
|
|
|
172
165
|
|
|
173
166
|
#: (*Symbol) { (Context) -> void } -> void
|
|
174
167
|
def before(*task_names, &block)
|
|
175
|
-
validate_namespace!
|
|
176
168
|
_workflow.add_hook(:before, task_names:, block:)
|
|
177
169
|
end
|
|
178
170
|
|
|
179
171
|
#: (*Symbol) { (Context) -> void } -> void
|
|
180
172
|
def after(*task_names, &block)
|
|
181
|
-
validate_namespace!
|
|
182
173
|
_workflow.add_hook(:after, task_names:, block:)
|
|
183
174
|
end
|
|
184
175
|
|
|
185
176
|
#: (*Symbol) { (Context, TaskCallable) -> void } -> void
|
|
186
177
|
def around(*task_names, &block)
|
|
187
|
-
validate_namespace!
|
|
188
178
|
_workflow.add_hook(:around, task_names:, block:)
|
|
189
179
|
end
|
|
190
180
|
|
|
191
181
|
#: (*Symbol) { (Context, StandardError, Task) -> void } -> void
|
|
192
182
|
def on_error(*task_names, &block)
|
|
193
|
-
validate_namespace!
|
|
194
183
|
_workflow.add_hook(:error, task_names:, block:)
|
|
195
184
|
end
|
|
196
185
|
|
|
@@ -240,7 +229,6 @@ module JobWorkflow
|
|
|
240
229
|
|
|
241
230
|
#: (?bool) ?{ (Context) -> bool } -> void
|
|
242
231
|
def dry_run(value = nil, &block)
|
|
243
|
-
validate_namespace!
|
|
244
232
|
_workflow.dry_run_config = block || value
|
|
245
233
|
end
|
|
246
234
|
|
|
@@ -254,7 +242,6 @@ module JobWorkflow
|
|
|
254
242
|
# ?description: String?
|
|
255
243
|
# ) -> void
|
|
256
244
|
def schedule(expression, key: nil, queue: nil, priority: nil, args: {}, description: nil)
|
|
257
|
-
validate_namespace!
|
|
258
245
|
_workflow.add_schedule(
|
|
259
246
|
Schedule.new(
|
|
260
247
|
expression:,
|
|
@@ -268,13 +255,6 @@ module JobWorkflow
|
|
|
268
255
|
)
|
|
269
256
|
end
|
|
270
257
|
# rubocop:enable Metrics/ParameterLists
|
|
271
|
-
|
|
272
|
-
private
|
|
273
|
-
|
|
274
|
-
#: () -> void
|
|
275
|
-
def validate_namespace!
|
|
276
|
-
raise "cannot be defined within a namespace." unless _workflow.namespace.default?
|
|
277
|
-
end
|
|
278
258
|
end
|
|
279
259
|
end
|
|
280
260
|
end
|
data/lib/job_workflow/runner.rb
CHANGED
|
@@ -15,12 +15,12 @@ module JobWorkflow
|
|
|
15
15
|
task = context._task_context.task
|
|
16
16
|
if !task.nil? && context.sub_job?
|
|
17
17
|
run_task(task)
|
|
18
|
-
|
|
18
|
+
persist_current_job_context
|
|
19
19
|
return
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
catch(:rescheduled) { run_workflow }
|
|
23
|
-
|
|
23
|
+
persist_current_job_context
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
private
|
|
@@ -50,7 +50,7 @@ module JobWorkflow
|
|
|
50
50
|
|
|
51
51
|
job.step(task.task_name) do |step|
|
|
52
52
|
wait_for_dependent_tasks(task, step)
|
|
53
|
-
task.enqueue.should_enqueue?(context) ? enqueue_task(task) : run_task(task)
|
|
53
|
+
task.enqueue.should_enqueue?(context) ? enqueue_task(task) : run_task(task, step:)
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
end
|
|
@@ -63,11 +63,12 @@ module JobWorkflow
|
|
|
63
63
|
result
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
#: (Task) -> void
|
|
67
|
-
def run_task(task)
|
|
66
|
+
#: (Task, ?step: ActiveJob::Continuation::Step?) -> void
|
|
67
|
+
def run_task(task, step: nil)
|
|
68
68
|
context._load_parent_task_output
|
|
69
|
-
context._with_each_value(task).each do |ctx|
|
|
69
|
+
context._with_each_value(task, start_index: step&.cursor).each do |ctx|
|
|
70
70
|
run_each_task(task, ctx)
|
|
71
|
+
step&.set!(ctx._task_context.index + 1)
|
|
71
72
|
rescue StandardError => e
|
|
72
73
|
run_error_hooks(task, ctx, e)
|
|
73
74
|
raise
|
|
@@ -112,6 +113,7 @@ module JobWorkflow
|
|
|
112
113
|
#: (Task) -> void
|
|
113
114
|
def enqueue_task(task)
|
|
114
115
|
sub_jobs = context._with_each_value(task).map { |ctx| job.class.from_context(ctx) }
|
|
116
|
+
persist_current_job_context
|
|
115
117
|
ActiveJob.perform_all_later(sub_jobs)
|
|
116
118
|
context.job_status.update_task_job_statuses_from_jobs(task_name: task.task_name, jobs: sub_jobs)
|
|
117
119
|
Instrumentation.notify_task_enqueue(job, task, sub_jobs.size)
|
|
@@ -175,5 +177,10 @@ module JobWorkflow
|
|
|
175
177
|
context_data_list = QueueAdapter.current.fetch_job_contexts(finished_job_ids)
|
|
176
178
|
context.output.update_task_outputs_from_contexts(context_data_list, context.workflow)
|
|
177
179
|
end
|
|
180
|
+
|
|
181
|
+
#: () -> void
|
|
182
|
+
def persist_current_job_context
|
|
183
|
+
QueueAdapter.current.persist_job_context(job)
|
|
184
|
+
end
|
|
178
185
|
end
|
|
179
186
|
end
|
data/lib/job_workflow/task.rb
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
module JobWorkflow
|
|
4
4
|
class Task
|
|
5
5
|
attr_reader :job_name #: String
|
|
6
|
-
attr_reader :namespace #: Namespace
|
|
7
6
|
attr_reader :block #: ^(untyped) -> void
|
|
8
7
|
attr_reader :each #: ^(Context) -> untyped
|
|
9
8
|
attr_reader :enqueue #: TaskEnqueue
|
|
@@ -16,11 +15,10 @@ module JobWorkflow
|
|
|
16
15
|
attr_reader :dependency_wait #: TaskDependencyWait
|
|
17
16
|
attr_reader :dry_run_config #: DryRunConfig
|
|
18
17
|
|
|
19
|
-
# rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
|
|
18
|
+
# rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
|
|
20
19
|
#: (
|
|
21
20
|
# job_name: String,
|
|
22
21
|
# name: Symbol,
|
|
23
|
-
# namespace: Namespace,
|
|
24
22
|
# block: ^(untyped) -> void,
|
|
25
23
|
# ?each: ^(Context) -> untyped,
|
|
26
24
|
# ?enqueue: true | false | ^(Context) -> bool | Hash[Symbol, untyped],
|
|
@@ -36,7 +34,6 @@ module JobWorkflow
|
|
|
36
34
|
def initialize(
|
|
37
35
|
job_name:,
|
|
38
36
|
name:,
|
|
39
|
-
namespace:,
|
|
40
37
|
block:,
|
|
41
38
|
each: nil,
|
|
42
39
|
enqueue: nil,
|
|
@@ -51,7 +48,6 @@ module JobWorkflow
|
|
|
51
48
|
)
|
|
52
49
|
@job_name = job_name
|
|
53
50
|
@name = name
|
|
54
|
-
@namespace = namespace #: Namespace
|
|
55
51
|
@block = block
|
|
56
52
|
@each = each
|
|
57
53
|
@enqueue = TaskEnqueue.from_primitive_value(enqueue)
|
|
@@ -64,11 +60,11 @@ module JobWorkflow
|
|
|
64
60
|
@dependency_wait = TaskDependencyWait.from_primitive_value(dependency_wait)
|
|
65
61
|
@dry_run_config = DryRunConfig.from_primitive_value(dry_run)
|
|
66
62
|
end
|
|
67
|
-
# rubocop:enable Metrics/ParameterLists, Metrics/MethodLength
|
|
63
|
+
# rubocop:enable Metrics/ParameterLists, Metrics/MethodLength
|
|
68
64
|
|
|
69
65
|
#: () -> Symbol
|
|
70
66
|
def task_name
|
|
71
|
-
|
|
67
|
+
name
|
|
72
68
|
end
|
|
73
69
|
|
|
74
70
|
#: () -> String
|
data/lib/job_workflow/version.rb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module JobWorkflow
|
|
4
4
|
class Workflow
|
|
5
|
-
attr_reader :namespace #: Namespace
|
|
6
5
|
attr_reader :dry_run_config #: DryRunConfig
|
|
7
6
|
|
|
8
7
|
#: () -> void
|
|
@@ -10,7 +9,6 @@ module JobWorkflow
|
|
|
10
9
|
@task_graph = TaskGraph.new
|
|
11
10
|
@argument_defs = {} #: Hash[Symbol, ArgumentDef]
|
|
12
11
|
@hook_registry = HookRegistry.new
|
|
13
|
-
@namespace = Namespace.default #: Namespace
|
|
14
12
|
@schedules = {} #: Hash[Symbol, Schedule]
|
|
15
13
|
@dry_run_config = DryRunConfig.new
|
|
16
14
|
end
|
|
@@ -20,15 +18,6 @@ module JobWorkflow
|
|
|
20
18
|
@dry_run_config = DryRunConfig.from_primitive_value(value)
|
|
21
19
|
end
|
|
22
20
|
|
|
23
|
-
#: (Namespace) { () -> void } -> void
|
|
24
|
-
def add_namespace(namespace)
|
|
25
|
-
original_namespace = @namespace
|
|
26
|
-
@namespace = namespace.update_parent(original_namespace)
|
|
27
|
-
yield
|
|
28
|
-
ensure
|
|
29
|
-
@namespace = original_namespace
|
|
30
|
-
end
|
|
31
|
-
|
|
32
21
|
#: (Task) -> void
|
|
33
22
|
def add_task(task)
|
|
34
23
|
@task_graph.add(task)
|
data/lib/job_workflow.rb
CHANGED
|
@@ -23,7 +23,6 @@ require_relative "job_workflow/task_throttle"
|
|
|
23
23
|
require_relative "job_workflow/task_enqueue"
|
|
24
24
|
require_relative "job_workflow/task_dependency_wait"
|
|
25
25
|
require_relative "job_workflow/semaphore"
|
|
26
|
-
require_relative "job_workflow/namespace"
|
|
27
26
|
require_relative "job_workflow/hook"
|
|
28
27
|
require_relative "job_workflow/error_hook"
|
|
29
28
|
require_relative "job_workflow/hook_registry"
|
data/rbs_collection.lock.yaml
CHANGED
|
@@ -6,7 +6,7 @@ gems:
|
|
|
6
6
|
source:
|
|
7
7
|
type: git
|
|
8
8
|
name: ruby/gem_rbs_collection
|
|
9
|
-
revision:
|
|
9
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
10
10
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
11
11
|
repo_dir: gems
|
|
12
12
|
- name: activerecord
|
|
@@ -14,7 +14,7 @@ gems:
|
|
|
14
14
|
source:
|
|
15
15
|
type: git
|
|
16
16
|
name: ruby/gem_rbs_collection
|
|
17
|
-
revision:
|
|
17
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
18
18
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
19
19
|
repo_dir: gems
|
|
20
20
|
- name: activesupport
|
|
@@ -22,7 +22,7 @@ gems:
|
|
|
22
22
|
source:
|
|
23
23
|
type: git
|
|
24
24
|
name: ruby/gem_rbs_collection
|
|
25
|
-
revision:
|
|
25
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
26
26
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
27
27
|
repo_dir: gems
|
|
28
28
|
- name: base64
|
|
@@ -34,7 +34,7 @@ gems:
|
|
|
34
34
|
source:
|
|
35
35
|
type: git
|
|
36
36
|
name: ruby/gem_rbs_collection
|
|
37
|
-
revision:
|
|
37
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
38
38
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
39
39
|
repo_dir: gems
|
|
40
40
|
- name: concurrent-ruby
|
|
@@ -42,7 +42,7 @@ gems:
|
|
|
42
42
|
source:
|
|
43
43
|
type: git
|
|
44
44
|
name: ruby/gem_rbs_collection
|
|
45
|
-
revision:
|
|
45
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
46
46
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
47
47
|
repo_dir: gems
|
|
48
48
|
- name: connection_pool
|
|
@@ -50,7 +50,7 @@ gems:
|
|
|
50
50
|
source:
|
|
51
51
|
type: git
|
|
52
52
|
name: ruby/gem_rbs_collection
|
|
53
|
-
revision:
|
|
53
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
54
54
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
55
55
|
repo_dir: gems
|
|
56
56
|
- name: date
|
|
@@ -74,7 +74,7 @@ gems:
|
|
|
74
74
|
source:
|
|
75
75
|
type: git
|
|
76
76
|
name: ruby/gem_rbs_collection
|
|
77
|
-
revision:
|
|
77
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
78
78
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
79
79
|
repo_dir: gems
|
|
80
80
|
- name: i18n
|
|
@@ -82,7 +82,7 @@ gems:
|
|
|
82
82
|
source:
|
|
83
83
|
type: git
|
|
84
84
|
name: ruby/gem_rbs_collection
|
|
85
|
-
revision:
|
|
85
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
86
86
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
87
87
|
repo_dir: gems
|
|
88
88
|
- name: json
|
|
@@ -98,7 +98,7 @@ gems:
|
|
|
98
98
|
source:
|
|
99
99
|
type: git
|
|
100
100
|
name: ruby/gem_rbs_collection
|
|
101
|
-
revision:
|
|
101
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
102
102
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
103
103
|
repo_dir: gems
|
|
104
104
|
- name: monitor
|
|
@@ -138,7 +138,7 @@ gems:
|
|
|
138
138
|
source:
|
|
139
139
|
type: git
|
|
140
140
|
name: ruby/gem_rbs_collection
|
|
141
|
-
revision:
|
|
141
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
142
142
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
143
143
|
repo_dir: gems
|
|
144
144
|
- name: stringio
|
|
@@ -162,7 +162,7 @@ gems:
|
|
|
162
162
|
source:
|
|
163
163
|
type: git
|
|
164
164
|
name: ruby/gem_rbs_collection
|
|
165
|
-
revision:
|
|
165
|
+
revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
|
|
166
166
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
167
167
|
repo_dir: gems
|
|
168
168
|
- name: uri
|
|
@@ -48,8 +48,8 @@ module JobWorkflow
|
|
|
48
48
|
# : () -> String?
|
|
49
49
|
def concurrency_key: () -> String?
|
|
50
50
|
|
|
51
|
-
# : (Task) -> Enumerator[Context]
|
|
52
|
-
def _with_each_value: (Task) -> Enumerator[Context]
|
|
51
|
+
# : (Task, ?start_index: Integer?) -> Enumerator[Context]
|
|
52
|
+
def _with_each_value: (Task, ?start_index: Integer?) -> Enumerator[Context]
|
|
53
53
|
|
|
54
54
|
# : () { () -> void } -> void
|
|
55
55
|
def _with_task_throttle: () { () -> void } -> void
|
|
@@ -128,14 +128,14 @@ module JobWorkflow
|
|
|
128
128
|
# : () -> Hash[String, untyped]
|
|
129
129
|
def serialize_for_sub_job: () -> Hash[String, untyped]
|
|
130
130
|
|
|
131
|
-
# : (Task, Enumerator::Yielder) -> void
|
|
132
|
-
def with_task_context: (Task, Enumerator::Yielder) -> void
|
|
131
|
+
# : (Task, Enumerator::Yielder, ?start_index: Integer?) -> void
|
|
132
|
+
def with_task_context: (Task, Enumerator::Yielder, ?start_index: Integer?) -> void
|
|
133
133
|
|
|
134
134
|
# : (Task) -> void
|
|
135
135
|
def reset_task_context_if_task_changed: (Task) -> void
|
|
136
136
|
|
|
137
|
-
# : (Task) { (untyped, Integer) -> void } -> void
|
|
138
|
-
def with_each_index_and_value: (Task) { (untyped, Integer) -> void } -> void
|
|
137
|
+
# : (Task, ?start_index: Integer?) { (untyped, Integer) -> void } -> void
|
|
138
|
+
def with_each_index_and_value: (Task, ?start_index: Integer?) { (untyped, Integer) -> void } -> void
|
|
139
139
|
|
|
140
140
|
# : () -> void
|
|
141
141
|
def clear_after_each_index_and_value: () -> void
|
|
@@ -62,9 +62,6 @@ module JobWorkflow
|
|
|
62
62
|
# : (Symbol argument_name, String type, ?default: untyped) -> void
|
|
63
63
|
def argument: (Symbol argument_name, String type, ?default: untyped) -> void
|
|
64
64
|
|
|
65
|
-
# : (Symbol) { () -> void } -> void
|
|
66
|
-
def namespace: (Symbol) { () -> void } -> void
|
|
67
|
-
|
|
68
65
|
# rubocop:disable Metrics/ParameterLists
|
|
69
66
|
#
|
|
70
67
|
# : (
|
|
@@ -139,11 +136,6 @@ module JobWorkflow
|
|
|
139
136
|
# ?description: String?
|
|
140
137
|
# ) -> void
|
|
141
138
|
def schedule: (String expression, ?key: (String | Symbol)?, ?queue: String?, ?priority: Integer?, ?args: Hash[Symbol, untyped], ?description: String?) -> void
|
|
142
|
-
|
|
143
|
-
private
|
|
144
|
-
|
|
145
|
-
# : () -> void
|
|
146
|
-
def validate_namespace!: () -> void
|
|
147
139
|
end
|
|
148
140
|
end
|
|
149
141
|
end
|
|
@@ -30,8 +30,8 @@ module JobWorkflow
|
|
|
30
30
|
# : (Task) -> bool
|
|
31
31
|
def skip_task?: (Task) -> bool
|
|
32
32
|
|
|
33
|
-
# : (Task) -> void
|
|
34
|
-
def run_task: (Task) -> void
|
|
33
|
+
# : (Task, ?step: ActiveJob::Continuation::Step?) -> void
|
|
34
|
+
def run_task: (Task, ?step: ActiveJob::Continuation::Step?) -> void
|
|
35
35
|
|
|
36
36
|
# : (Task, Context) -> void
|
|
37
37
|
def run_each_task: (Task, Context) -> void
|
|
@@ -62,5 +62,8 @@ module JobWorkflow
|
|
|
62
62
|
|
|
63
63
|
# : (Task) -> void
|
|
64
64
|
def update_task_outputs: (Task) -> void
|
|
65
|
+
|
|
66
|
+
# : () -> void
|
|
67
|
+
def persist_current_job_context: () -> void
|
|
65
68
|
end
|
|
66
69
|
end
|
|
@@ -4,8 +4,6 @@ module JobWorkflow
|
|
|
4
4
|
class Task
|
|
5
5
|
attr_reader job_name: String
|
|
6
6
|
|
|
7
|
-
attr_reader namespace: Namespace
|
|
8
|
-
|
|
9
7
|
attr_reader block: ^(untyped) -> void
|
|
10
8
|
|
|
11
9
|
attr_reader each: ^(Context) -> untyped
|
|
@@ -28,11 +26,10 @@ module JobWorkflow
|
|
|
28
26
|
|
|
29
27
|
attr_reader dry_run_config: DryRunConfig
|
|
30
28
|
|
|
31
|
-
# rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
|
|
29
|
+
# rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
|
|
32
30
|
# : (
|
|
33
31
|
# job_name: String,
|
|
34
32
|
# name: Symbol,
|
|
35
|
-
# namespace: Namespace,
|
|
36
33
|
# block: ^(untyped) -> void,
|
|
37
34
|
# ?each: ^(Context) -> untyped,
|
|
38
35
|
# ?enqueue: true | false | ^(Context) -> bool | Hash[Symbol, untyped],
|
|
@@ -45,7 +42,7 @@ module JobWorkflow
|
|
|
45
42
|
# ?dependency_wait: Hash[Symbol, untyped],
|
|
46
43
|
# ?dry_run: bool | ^(Context) -> bool
|
|
47
44
|
# ) -> void
|
|
48
|
-
def initialize: (job_name: String, name: Symbol,
|
|
45
|
+
def initialize: (job_name: String, name: Symbol, block: ^(untyped) -> void, condition: ^(Context) -> bool, ?each: ^(Context) -> untyped, ?enqueue: true | false | ^(Context) -> bool | Hash[Symbol, untyped], ?output: Hash[Symbol, String], ?depends_on: Array[Symbol], ?task_retry: Integer | Hash[Symbol, untyped], ?throttle: Integer | Hash[Symbol, untyped], ?timeout: Numeric?, ?dependency_wait: Hash[Symbol, untyped], ?dry_run: bool | ^(Context) -> bool) -> void
|
|
49
46
|
|
|
50
47
|
# : () -> Symbol
|
|
51
48
|
def task_name: () -> Symbol
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module JobWorkflow
|
|
4
4
|
class Workflow
|
|
5
|
-
attr_reader namespace: Namespace
|
|
6
|
-
|
|
7
5
|
attr_reader dry_run_config: DryRunConfig
|
|
8
6
|
|
|
9
7
|
# : () -> void
|
|
@@ -12,9 +10,6 @@ module JobWorkflow
|
|
|
12
10
|
# : (bool | ^(Context) -> bool) -> void
|
|
13
11
|
def dry_run_config=: (bool | ^(Context) -> bool) -> void
|
|
14
12
|
|
|
15
|
-
# : (Namespace) { () -> void } -> void
|
|
16
|
-
def add_namespace: (Namespace) { () -> void } -> void
|
|
17
|
-
|
|
18
13
|
# : (Task) -> void
|
|
19
14
|
def add_task: (Task) -> void
|
|
20
15
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: job-workflow
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- shoma07
|
|
@@ -49,7 +49,6 @@ files:
|
|
|
49
49
|
- guides/GETTING_STARTED.md
|
|
50
50
|
- guides/INSTRUMENTATION.md
|
|
51
51
|
- guides/LIFECYCLE_HOOKS.md
|
|
52
|
-
- guides/NAMESPACES.md
|
|
53
52
|
- guides/OPENTELEMETRY_INTEGRATION.md
|
|
54
53
|
- guides/PARALLEL_PROCESSING.md
|
|
55
54
|
- guides/PRODUCTION_DEPLOYMENT.md
|
|
@@ -84,7 +83,6 @@ files:
|
|
|
84
83
|
- lib/job_workflow/instrumentation/opentelemetry_subscriber.rb
|
|
85
84
|
- lib/job_workflow/job_status.rb
|
|
86
85
|
- lib/job_workflow/logger.rb
|
|
87
|
-
- lib/job_workflow/namespace.rb
|
|
88
86
|
- lib/job_workflow/output.rb
|
|
89
87
|
- lib/job_workflow/output_def.rb
|
|
90
88
|
- lib/job_workflow/queue.rb
|
|
@@ -136,7 +134,6 @@ files:
|
|
|
136
134
|
- sig/generated/job_workflow/instrumentation/opentelemetry_subscriber.rbs
|
|
137
135
|
- sig/generated/job_workflow/job_status.rbs
|
|
138
136
|
- sig/generated/job_workflow/logger.rbs
|
|
139
|
-
- sig/generated/job_workflow/namespace.rbs
|
|
140
137
|
- sig/generated/job_workflow/output.rbs
|
|
141
138
|
- sig/generated/job_workflow/output_def.rbs
|
|
142
139
|
- sig/generated/job_workflow/queue.rbs
|
data/guides/NAMESPACES.md
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# Namespaces
|
|
2
|
-
|
|
3
|
-
Logically grouping tasks improves readability and maintainability of complex workflows. JobWorkflow provides namespace functionality.
|
|
4
|
-
|
|
5
|
-
## Basic Namespaces
|
|
6
|
-
|
|
7
|
-
### namespace DSL
|
|
8
|
-
|
|
9
|
-
Group related tasks.
|
|
10
|
-
|
|
11
|
-
```ruby
|
|
12
|
-
class ECommerceOrderJob < ApplicationJob
|
|
13
|
-
include JobWorkflow::DSL
|
|
14
|
-
|
|
15
|
-
argument :order, "Order"
|
|
16
|
-
|
|
17
|
-
# Payment-related tasks
|
|
18
|
-
namespace :payment do
|
|
19
|
-
task :validate do |ctx|
|
|
20
|
-
order = ctx.arguments.order
|
|
21
|
-
PaymentValidator.validate(order)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
task :charge, depends_on: [:"payment:validate"], output: { payment_result: "Hash" } do |ctx|
|
|
25
|
-
order = ctx.arguments.order
|
|
26
|
-
{ payment_result: PaymentProcessor.charge(order) }
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
task :send_receipt, depends_on: [:"payment:charge"] do |ctx|
|
|
30
|
-
order = ctx.arguments.order
|
|
31
|
-
payment_result = ctx.output[:"payment:charge"].first.payment_result
|
|
32
|
-
ReceiptMailer.send(order, payment_result)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Inventory-related tasks
|
|
37
|
-
namespace :inventory do
|
|
38
|
-
task :check_availability do |ctx|
|
|
39
|
-
order = ctx.arguments.order
|
|
40
|
-
InventoryService.check(order.items)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
task :reserve, depends_on: [:"inventory:check_availability"], output: { reserved: "bool" } do |ctx|
|
|
44
|
-
order = ctx.arguments.order
|
|
45
|
-
{ reserved: InventoryService.reserve(order.items) }
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Shipping-related tasks
|
|
50
|
-
namespace :shipping do
|
|
51
|
-
task :calculate_cost, output: { shipping_cost: "Float" } do |ctx|
|
|
52
|
-
order = ctx.arguments.order
|
|
53
|
-
{ shipping_cost: ShippingCalculator.calculate(order) }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
task :create_label, depends_on: [:"shipping:calculate_cost"], output: { shipping_label: "String" } do |ctx|
|
|
57
|
-
order = ctx.arguments.order
|
|
58
|
-
{ shipping_label: ShippingService.create_label(order) }
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Tasks in namespaces are identified as `:namespace:task_name` at runtime:
|
|
65
|
-
|
|
66
|
-
```ruby
|
|
67
|
-
# Executed tasks:
|
|
68
|
-
# - :payment:validate
|
|
69
|
-
# - :payment:charge
|
|
70
|
-
# - :payment:send_receipt
|
|
71
|
-
# - :inventory:check_availability
|
|
72
|
-
# - :inventory:reserve
|
|
73
|
-
# - :shipping:calculate_cost
|
|
74
|
-
# - :shipping:create_label
|
|
75
|
-
```
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JobWorkflow
|
|
4
|
-
class Namespace
|
|
5
|
-
attr_reader :name #: Symbol
|
|
6
|
-
attr_reader :parent #: Namespace?
|
|
7
|
-
|
|
8
|
-
class << self
|
|
9
|
-
#: () -> Namespace
|
|
10
|
-
def default
|
|
11
|
-
new(name: :"")
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
#: (name: Symbol, ?parent: Namespace?) -> void
|
|
16
|
-
def initialize(name:, parent: nil)
|
|
17
|
-
@name = name #: Symbol
|
|
18
|
-
@parent = parent #: Namespace?
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
#: () -> bool
|
|
22
|
-
def default?
|
|
23
|
-
name.empty?
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
#: (Namespace) -> Namespace
|
|
27
|
-
def update_parent(parent)
|
|
28
|
-
self.class.new(name:, parent:)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
#: () -> Symbol
|
|
32
|
-
def full_name
|
|
33
|
-
[parent&.full_name, name.to_s].compact.reject(&:empty?).join(":").to_sym
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Generated from lib/job_workflow/namespace.rb with RBS::Inline
|
|
2
|
-
|
|
3
|
-
module JobWorkflow
|
|
4
|
-
class Namespace
|
|
5
|
-
attr_reader name: Symbol
|
|
6
|
-
|
|
7
|
-
attr_reader parent: Namespace?
|
|
8
|
-
|
|
9
|
-
# : () -> Namespace
|
|
10
|
-
def self.default: () -> Namespace
|
|
11
|
-
|
|
12
|
-
# : (name: Symbol, ?parent: Namespace?) -> void
|
|
13
|
-
def initialize: (name: Symbol, ?parent: Namespace?) -> void
|
|
14
|
-
|
|
15
|
-
# : () -> bool
|
|
16
|
-
def default?: () -> bool
|
|
17
|
-
|
|
18
|
-
# : (Namespace) -> Namespace
|
|
19
|
-
def update_parent: (Namespace) -> Namespace
|
|
20
|
-
|
|
21
|
-
# : () -> Symbol
|
|
22
|
-
def full_name: () -> Symbol
|
|
23
|
-
end
|
|
24
|
-
end
|