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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a4a82b69372293b7bf689c33125b60b4cbdbcdf4f2e1f468e205cf9bf0c1d85
4
- data.tar.gz: e2e6e91167d6127e6cee7e2af0339f79ffee244fe6e768d73e50ebb6c2e7b372
3
+ metadata.gz: 213a0654cb0482f1a2574f4e55d26c72f5274d24b61b933abd04e9e21f4c19d1
4
+ data.tar.gz: 0f19fce390ff18dcb13d80c8a4c6841dc2e096d4ea7586f0a2d6e2c6a467a45b
5
5
  SHA512:
6
- metadata.gz: 84356b092c371e103d601576f9fc6ed5cdee9025340948b0d1fe8222b5b1f49f301342f8254a0d858fc89da58e8f828241d7d8ec706103349e63d6f68a426945
7
- data.tar.gz: b146df16edb3112fa10379437e03ebd6a7f74c46e3a83526bb195320e141e9493319caa96d601622cf1e2f5d8cf18b071cc56c93aac1ad39492b89cfa8e08392
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.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.
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.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.
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.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.
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
@@ -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 < task_context.index
302
+ next if index < resume_index
301
303
 
302
304
  yield value, index
303
305
 
@@ -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
@@ -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
- QueueAdapter.current.persist_job_context(job)
18
+ persist_current_job_context
19
19
  return
20
20
  end
21
21
 
22
22
  catch(:rescheduled) { run_workflow }
23
- QueueAdapter.current.persist_job_context(job)
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
@@ -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, Metrics/AbcSize
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, Metrics/AbcSize
63
+ # rubocop:enable Metrics/ParameterLists, Metrics/MethodLength
68
64
 
69
65
  #: () -> Symbol
70
66
  def task_name
71
- [namespace.full_name.to_s, name.to_s].reject(&:empty?).join(":").to_sym
67
+ name
72
68
  end
73
69
 
74
70
  #: () -> String
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JobWorkflow
4
- VERSION = "0.3.0" # : String
4
+ VERSION = "0.4.0" # : String
5
5
  end
@@ -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"
@@ -6,7 +6,7 @@ gems:
6
6
  source:
7
7
  type: git
8
8
  name: ruby/gem_rbs_collection
9
- revision: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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: 9bf2eebb1c54b5d6f23f2acb65d4c36f195b4783
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, Metrics/AbcSize
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, namespace: Namespace, 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
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.3.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