job-workflow 0.5.0 → 0.6.1

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.agents/instructions/coding-style.md +38 -0
  3. data/.agents/instructions/domain.md +37 -0
  4. data/.agents/instructions/environment.md +44 -0
  5. data/.agents/instructions/general.md +29 -0
  6. data/.agents/instructions/security.md +20 -0
  7. data/.agents/instructions/structure.md +43 -0
  8. data/.agents/instructions/tech-stack.md +40 -0
  9. data/.agents/instructions/testing.md +46 -0
  10. data/.agents/instructions/workflow.md +39 -0
  11. data/.rubocop.yml +1 -2
  12. data/AGENTS.md +23 -0
  13. data/CHANGELOG.md +26 -0
  14. data/README.md +1 -1
  15. data/app/controllers/job_workflow/monitoring/application_controller.rb +11 -0
  16. data/app/controllers/job_workflow/monitoring/executions_controller.rb +28 -0
  17. data/app/controllers/job_workflow/monitoring/workflows_controller.rb +11 -0
  18. data/app/views/job_workflow/monitoring/executions/index.html.erb +57 -0
  19. data/app/views/job_workflow/monitoring/executions/show.html.erb +200 -0
  20. data/app/views/job_workflow/monitoring/workflows/index.html.erb +39 -0
  21. data/app/views/layouts/job_workflow/monitoring/application.html.erb +117 -0
  22. data/config/routes.rb +8 -0
  23. data/guides/API_REFERENCE.md +9 -6
  24. data/guides/DEPENDENCY_WAIT.md +9 -5
  25. data/guides/MONITORING_UI.md +74 -0
  26. data/guides/PARALLEL_PROCESSING.md +33 -21
  27. data/guides/PRODUCTION_DEPLOYMENT.md +1 -1
  28. data/guides/README.md +6 -1
  29. data/guides/THROTTLING.md +24 -0
  30. data/guides/WORKFLOW_STATUS_QUERY.md +7 -1
  31. data/lib/job_workflow/context.rb +7 -5
  32. data/lib/job_workflow/dsl.rb +0 -4
  33. data/lib/job_workflow/instrumentation/opentelemetry_subscriber.rb +1 -1
  34. data/lib/job_workflow/instrumentation.rb +14 -14
  35. data/lib/job_workflow/job_status.rb +16 -1
  36. data/lib/job_workflow/monitoring/dag_layout.rb +186 -0
  37. data/lib/job_workflow/monitoring/engine.rb +15 -0
  38. data/lib/job_workflow/monitoring/execution_page.rb +16 -0
  39. data/lib/job_workflow/monitoring/execution_registry.rb +50 -0
  40. data/lib/job_workflow/monitoring/execution_view_model.rb +258 -0
  41. data/lib/job_workflow/monitoring/parameter_filter.rb +37 -0
  42. data/lib/job_workflow/monitoring/workflow_definition.rb +24 -0
  43. data/lib/job_workflow/monitoring/workflow_registry.rb +24 -0
  44. data/lib/job_workflow/monitoring.rb +120 -0
  45. data/lib/job_workflow/queue_adapters/abstract.rb +7 -2
  46. data/lib/job_workflow/queue_adapters/null_adapter.rb +12 -1
  47. data/lib/job_workflow/queue_adapters/solid_queue_adapter.rb +42 -12
  48. data/lib/job_workflow/railtie.rb +2 -0
  49. data/lib/job_workflow/runner.rb +5 -3
  50. data/lib/job_workflow/sub_task_job.rb +93 -0
  51. data/lib/job_workflow/task_enqueue.rb +19 -12
  52. data/lib/job_workflow/version.rb +1 -1
  53. data/lib/job_workflow/workflow_status.rb +39 -3
  54. data/lib/job_workflow.rb +2 -0
  55. data/rbs_collection.lock.yaml +11 -11
  56. data/sig/generated/job_workflow/context.rbs +7 -7
  57. data/sig/generated/job_workflow/instrumentation/opentelemetry_subscriber.rbs +0 -1
  58. data/sig/generated/job_workflow/instrumentation.rbs +28 -28
  59. data/sig/generated/job_workflow/job_status.rbs +5 -2
  60. data/sig/generated/job_workflow/monitoring/dag_layout.rbs +80 -0
  61. data/sig/generated/job_workflow/monitoring/engine.rbs +8 -0
  62. data/sig/generated/job_workflow/monitoring/execution_page.rbs +14 -0
  63. data/sig/generated/job_workflow/monitoring/execution_registry.rbs +21 -0
  64. data/sig/generated/job_workflow/monitoring/execution_view_model.rbs +111 -0
  65. data/sig/generated/job_workflow/monitoring/parameter_filter.rbs +16 -0
  66. data/sig/generated/job_workflow/monitoring/workflow_definition.rbs +18 -0
  67. data/sig/generated/job_workflow/monitoring/workflow_registry.rbs +13 -0
  68. data/sig/generated/job_workflow/monitoring.rbs +38 -0
  69. data/sig/generated/job_workflow/queue_adapters/abstract.rbs +7 -4
  70. data/sig/generated/job_workflow/queue_adapters/null_adapter.rbs +5 -2
  71. data/sig/generated/job_workflow/queue_adapters/solid_queue_adapter.rbs +18 -6
  72. data/sig/generated/job_workflow/runner.rbs +1 -1
  73. data/sig/generated/job_workflow/sub_task_job.rbs +40 -0
  74. data/sig/generated/job_workflow/task_enqueue.rbs +5 -8
  75. data/sig/generated/job_workflow/workflow_status.rbs +18 -2
  76. data/sig-private/job-workflow.rbs +11 -0
  77. data/sig-private/rails.rbs +5 -0
  78. metadata +42 -1
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JobWorkflow
4
+ class SubTaskJob < ActiveJob::Base
5
+ include ActiveJob::Continuable
6
+
7
+ class << self
8
+ #: (context: Context) -> SubTaskJob
9
+ def from_parent_context(context:)
10
+ validate_sub_task_context!(context)
11
+
12
+ new_context = context.dup
13
+ job = new(context.arguments.to_h)
14
+ new_context._job = job
15
+ job._context = new_context
16
+ task = new_context._task_context.task || (raise "task is not set")
17
+ return job if task.enqueue.queue.nil?
18
+
19
+ job.set(queue: task.enqueue.queue)
20
+ end
21
+
22
+ private
23
+
24
+ #: (Context) -> void
25
+ def validate_sub_task_context!(context)
26
+ task_context = context._task_context
27
+ raise ArgumentError, "task_context.task is required" if task_context.task.nil?
28
+ raise ArgumentError, "task_context.parent_job_id is required" if task_context.parent_job_id.nil?
29
+ end
30
+ end
31
+
32
+ #: (Hash[untyped, untyped]) -> void
33
+ def perform(arguments)
34
+ payload = arguments.symbolize_keys
35
+ self._context = build_context(payload)
36
+ Runner.new(context: _context).run
37
+ end
38
+
39
+ #: () -> Output
40
+ def output
41
+ context = _context
42
+ raise "context is not set." if context.nil?
43
+
44
+ context.output
45
+ end
46
+
47
+ attr_accessor :_context #: Context?
48
+
49
+ #: () -> Hash[String, untyped]
50
+ def serialize
51
+ super.merge({ "job_workflow_context" => _context&.serialize || serialized_job_workflow_context }.compact)
52
+ end
53
+
54
+ #: (Hash[String, untyped]) -> void
55
+ def deserialize(job_data)
56
+ super
57
+ self.serialized_job_workflow_context = job_data["job_workflow_context"]
58
+ end
59
+
60
+ private
61
+
62
+ attr_accessor :serialized_job_workflow_context #: Hash[String, untyped]?
63
+
64
+ #: (Hash[Symbol, untyped]) -> Context
65
+ def build_context(payload)
66
+ context_data = extract_context_data(payload)
67
+ parent_job_id = context_data.fetch("task_context").fetch("parent_job_id")
68
+ parent_job_data = QueueAdapter.current.find_job(parent_job_id)
69
+ raise WorkflowStatus::NotFoundError, "Workflow with job_id '#{parent_job_id}' not found" if parent_job_data.nil?
70
+
71
+ workflow = resolve_workflow(parent_job_data.fetch("class_name"))
72
+ Context.deserialize(context_data.merge("job" => self, "workflow" => workflow))
73
+ ._update_arguments(payload.except(:job_workflow_context))
74
+ end
75
+
76
+ #: (job_class_name: String) -> Workflow
77
+ def resolve_workflow(job_class_name)
78
+ job_class = JobWorkflow::DSL._included_classes.to_a.reverse.find { |klass| klass.name == job_class_name }
79
+ job_class ||= job_class_name.safe_constantize
80
+ raise NameError, "uninitialized constant #{job_class_name}" if job_class.nil?
81
+
82
+ job_class._workflow
83
+ end
84
+
85
+ #: (Hash[Symbol, untyped]) -> Hash[String, untyped]
86
+ def extract_context_data(payload)
87
+ context_data = serialized_job_workflow_context || payload[:job_workflow_context]
88
+ raise "job_workflow_context is not set." if context_data.nil?
89
+
90
+ context_data.deep_stringify_keys
91
+ end
92
+ end
93
+ end
@@ -4,7 +4,6 @@ module JobWorkflow
4
4
  class TaskEnqueue
5
5
  attr_reader :condition #: true | false | ^(Context) -> bool
6
6
  attr_reader :queue #: String?
7
- attr_reader :concurrency #: Integer?
8
7
 
9
8
  class << self
10
9
  #: (true | false | ^(Context) -> bool | Hash[Symbol, untyped] | nil) -> TaskEnqueue
@@ -13,26 +12,39 @@ module JobWorkflow
13
12
  when TrueClass, FalseClass, Proc
14
13
  new(condition: value)
15
14
  when Hash
15
+ validate_hash_keys!(value)
16
+
16
17
  new(
17
18
  condition: value.fetch(:condition, !value.empty?),
18
- queue: value[:queue],
19
- concurrency: value[:concurrency]
19
+ queue: value[:queue]
20
20
  )
21
21
  else
22
22
  new
23
23
  end
24
24
  end
25
+
26
+ private
27
+
28
+ #: (Hash[Symbol, untyped]) -> void
29
+ def validate_hash_keys!(value)
30
+ unsupported_keys = value.keys - %i[condition queue]
31
+ return if unsupported_keys.empty?
32
+
33
+ if unsupported_keys == %i[concurrency]
34
+ raise ArgumentError, "enqueue does not support :concurrency; use throttle instead"
35
+ end
36
+
37
+ raise ArgumentError, "enqueue supports only :condition and :queue"
38
+ end
25
39
  end
26
40
 
27
41
  #: (
28
42
  # ?condition: true | false | ^(Context) -> bool,
29
- # ?queue: String?,
30
- # ?concurrency: Integer?
43
+ # ?queue: String?
31
44
  # ) -> void
32
- def initialize(condition: false, queue: nil, concurrency: nil)
45
+ def initialize(condition: false, queue: nil)
33
46
  @condition = condition
34
47
  @queue = queue
35
- @concurrency = concurrency
36
48
  end
37
49
 
38
50
  #: (Context) -> bool
@@ -41,10 +53,5 @@ module JobWorkflow
41
53
 
42
54
  !!condition
43
55
  end
44
-
45
- #: () -> bool
46
- def should_limits_concurrency?
47
- !!condition && !concurrency.nil? && QueueAdapter.current.supports_concurrency_limits?
48
- end
49
56
  end
50
57
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JobWorkflow
4
- VERSION = "0.5.0" # : String
4
+ VERSION = "0.6.1" # : String
5
5
  end
@@ -10,6 +10,7 @@ module JobWorkflow
10
10
  attr_reader :context #: Context
11
11
  attr_reader :job_class_name #: String
12
12
  attr_reader :status #: status_type
13
+ attr_reader :completed_task_names #: Array[Symbol]
13
14
 
14
15
  class << self
15
16
  #: (String) -> WorkflowStatus
@@ -24,6 +25,7 @@ module JobWorkflow
24
25
  def find_by(job_id:)
25
26
  data = QueueAdapter.current.find_job(job_id)
26
27
  return if data.nil?
28
+ return if data["class_name"] == JobWorkflow::SubTaskJob.name
27
29
 
28
30
  WorkflowStatus.from_job_data(data)
29
31
  end
@@ -33,23 +35,57 @@ module JobWorkflow
33
35
  job_class_name = data["class_name"]
34
36
  job_class = job_class_name.constantize
35
37
  workflow = job_class._workflow
38
+ context = context_from_job_data(data, workflow)
39
+
40
+ new(
41
+ context:,
42
+ job_class_name:,
43
+ status: data["status"],
44
+ completed_task_names: completed_task_names_from_job_data(data)
45
+ )
46
+ end
47
+
48
+ private
49
+
50
+ #: (Hash[String, untyped]) -> Array[Symbol]
51
+ def completed_task_names_from_job_data(data)
52
+ Array(data.dig("continuation", "completed")).map(&:to_sym)
53
+ end
36
54
 
55
+ #: (Hash[String, untyped], Workflow) -> Context
56
+ def context_from_job_data(data, workflow)
37
57
  context_data = data["job_workflow_context"] || data["arguments"]&.first&.dig("job_workflow_context")
38
58
  context = if context_data
39
59
  Context.deserialize(context_data.merge("workflow" => workflow))
40
60
  else
41
61
  Context.from_hash({ workflow: })
42
62
  end
63
+ serialized_arguments = workflow_arguments_data(data)
64
+ return context if serialized_arguments.nil?
65
+
66
+ context._update_arguments(ActiveJob::Arguments.deserialize([serialized_arguments]).first)
67
+ end
68
+
69
+ #: (Hash[String, untyped]) -> Hash[String, untyped]?
70
+ def workflow_arguments_data(data)
71
+ serialized_arguments = data["arguments"]&.first
72
+ return if serialized_arguments.nil? || serialized_arguments.key?("job_workflow_context")
43
73
 
44
- new(context:, job_class_name:, status: data["status"])
74
+ serialized_arguments
45
75
  end
46
76
  end
47
77
 
48
- #: (context: Context, job_class_name: String, status: status_type) -> void
49
- def initialize(context:, job_class_name:, status:)
78
+ #: (
79
+ # context: Context,
80
+ # job_class_name: String,
81
+ # status: status_type,
82
+ # ?completed_task_names: Array[Symbol]
83
+ # ) -> void
84
+ def initialize(context:, job_class_name:, status:, completed_task_names: [])
50
85
  @context = context #: Context
51
86
  @job_class_name = job_class_name #: String
52
87
  @status = status #: Symbol
88
+ @completed_task_names = completed_task_names
53
89
  end
54
90
 
55
91
  #: () -> Symbol?
data/lib/job_workflow.rb CHANGED
@@ -31,6 +31,7 @@ require_relative "job_workflow/task"
31
31
  require_relative "job_workflow/task_graph"
32
32
  require_relative "job_workflow/schedule"
33
33
  require_relative "job_workflow/dsl"
34
+ require_relative "job_workflow/sub_task_job"
34
35
  require_relative "job_workflow/runner"
35
36
  require_relative "job_workflow/workflow_status"
36
37
  require_relative "job_workflow/workflow"
@@ -44,6 +45,7 @@ require_relative "job_workflow/output_def"
44
45
  require_relative "job_workflow/task_output"
45
46
  require_relative "job_workflow/output"
46
47
  require_relative "job_workflow/queue"
48
+ require_relative "job_workflow/monitoring"
47
49
  require_relative "job_workflow/auto_scaling"
48
50
  # :nocov:
49
51
  require_relative "job_workflow/railtie" if defined?(Rails::Railtie)
@@ -6,7 +6,7 @@ gems:
6
6
  source:
7
7
  type: git
8
8
  name: ruby/gem_rbs_collection
9
- revision: 81fa8bd0617286078617a62b6a3229cebfd4af23
9
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
17
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
25
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
37
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
45
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
53
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
77
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
85
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
101
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
141
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
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: 81fa8bd0617286078617a62b6a3229cebfd4af23
165
+ revision: 3f5e8df1ce89ea06067fa42263012c968b4e583e
166
166
  remote: https://github.com/ruby/gem_rbs_collection.git
167
167
  repo_dir: gems
168
168
  - name: uri
@@ -25,9 +25,9 @@ module JobWorkflow
25
25
  # task_context: TaskContext,
26
26
  # output: Output,
27
27
  # job_status: JobStatus,
28
- # ?job: DSL?
28
+ # ?job: _JobInterface?
29
29
  # ) -> void
30
- def initialize: (workflow: Workflow, arguments: Arguments, task_context: TaskContext, output: Output, job_status: JobStatus, ?job: DSL?) -> void
30
+ def initialize: (workflow: Workflow, arguments: Arguments, task_context: TaskContext, output: Output, job_status: JobStatus, ?job: _JobInterface?) -> void
31
31
 
32
32
  # : () -> Hash[String, untyped]
33
33
  def serialize: () -> Hash[String, untyped]
@@ -44,11 +44,11 @@ module JobWorkflow
44
44
  # : () -> void
45
45
  def checkpoint!: () -> void
46
46
 
47
- # : (DSL) -> void
48
- def _job=: (DSL) -> void
47
+ # : (_JobInterface) -> void
48
+ def _job=: (_JobInterface) -> void
49
49
 
50
- # : () -> DSL?
51
- def _job: () -> DSL?
50
+ # : () -> _JobInterface?
51
+ def _job: () -> _JobInterface?
52
52
 
53
53
  # : () -> String
54
54
  def job_id: () -> String
@@ -115,7 +115,7 @@ module JobWorkflow
115
115
 
116
116
  private
117
117
 
118
- attr_accessor job: DSL?
118
+ attr_accessor job: _JobInterface?
119
119
 
120
120
  attr_writer workflow: Workflow
121
121
 
@@ -19,7 +19,6 @@ module JobWorkflow
19
19
  # @note This subscriber requires the opentelemetry-api gem to be installed.
20
20
  # If not available, subscription will be silently skipped.
21
21
  class OpenTelemetrySubscriber
22
- # rubocop:disable Metrics/ClassLength
23
22
  module Attributes
24
23
  JOB_NAME: String
25
24
 
@@ -63,26 +63,26 @@ module JobWorkflow
63
63
  DRY_RUN_EXECUTE: untyped
64
64
  end
65
65
 
66
- # : (DSL) { () -> untyped } -> untyped
67
- def self.instrument_workflow: (DSL) { () -> untyped } -> untyped
66
+ # : (_JobInterface) { () -> untyped } -> untyped
67
+ def self.instrument_workflow: (_JobInterface) { () -> untyped } -> untyped
68
68
 
69
- # : (DSL, Task, Context) { () -> untyped } -> untyped
70
- def self.instrument_task: (DSL, Task, Context) { () -> untyped } -> untyped
69
+ # : (_JobInterface, Task, Context) { () -> untyped } -> untyped
70
+ def self.instrument_task: (_JobInterface, Task, Context) { () -> untyped } -> untyped
71
71
 
72
- # : (DSL, Task, String) -> void
73
- def self.notify_task_skip: (DSL, Task, String) -> void
72
+ # : (_JobInterface, Task, String) -> void
73
+ def self.notify_task_skip: (_JobInterface, Task, String) -> void
74
74
 
75
- # : (DSL, Task, Integer) -> void
76
- def self.notify_task_enqueue: (DSL, Task, Integer) -> void
75
+ # : (_JobInterface, Task, Integer) -> void
76
+ def self.notify_task_enqueue: (_JobInterface, Task, Integer) -> void
77
77
 
78
78
  # : (Task, Context, String, Integer, Float, StandardError) -> void
79
79
  def self.notify_task_retry: (Task, Context, String, Integer, Float, StandardError) -> void
80
80
 
81
- # : (DSL, Task) { () -> untyped } -> untyped
82
- def self.instrument_dependent_wait: (DSL, Task) { () -> untyped } -> untyped
81
+ # : (_JobInterface, Task) { () -> untyped } -> untyped
82
+ def self.instrument_dependent_wait: (_JobInterface, Task) { () -> untyped } -> untyped
83
83
 
84
- # : (DSL, Task, Numeric, Integer) -> void
85
- def self.notify_dependent_reschedule: (DSL, Task, Numeric, Integer) -> void
84
+ # : (_JobInterface, Task, Numeric, Integer) -> void
85
+ def self.notify_dependent_reschedule: (_JobInterface, Task, Numeric, Integer) -> void
86
86
 
87
87
  # : (Semaphore) { () -> untyped } -> untyped
88
88
  def self.instrument_throttle: (Semaphore) { () -> untyped } -> untyped
@@ -99,32 +99,32 @@ module JobWorkflow
99
99
  # : (String, Hash[Symbol, untyped]) { () -> untyped } -> untyped
100
100
  def self.instrument_custom: (String, Hash[Symbol, untyped]) { () -> untyped } -> untyped
101
101
 
102
- # : (DSL, Context, Symbol?, Integer, bool) { () -> untyped } -> untyped
103
- def self.instrument_dry_run: (DSL, Context, Symbol?, Integer, bool) { () -> untyped } -> untyped
102
+ # : (_JobInterface, Context, Symbol?, Integer, bool) { () -> untyped } -> untyped
103
+ def self.instrument_dry_run: (_JobInterface, Context, Symbol?, Integer, bool) { () -> untyped } -> untyped
104
104
 
105
105
  # : (String, Hash[Symbol, untyped]) ?{ () -> untyped } -> untyped
106
106
  private def self.instrument: (String, Hash[Symbol, untyped]) ?{ () -> untyped } -> untyped
107
107
 
108
- # : (DSL) -> Hash[Symbol, untyped]
109
- private def self.build_workflow_payload: (DSL) -> Hash[Symbol, untyped]
108
+ # : (_JobInterface) -> Hash[Symbol, untyped]
109
+ private def self.build_workflow_payload: (_JobInterface) -> Hash[Symbol, untyped]
110
110
 
111
- # : (DSL, Task, Context) -> Hash[Symbol, untyped]
112
- private def self.build_task_payload: (DSL, Task, Context) -> Hash[Symbol, untyped]
111
+ # : (_JobInterface, Task, Context) -> Hash[Symbol, untyped]
112
+ private def self.build_task_payload: (_JobInterface, Task, Context) -> Hash[Symbol, untyped]
113
113
 
114
- # : (DSL, Task, String) -> Hash[Symbol, untyped]
115
- private def self.build_task_skip_payload: (DSL, Task, String) -> Hash[Symbol, untyped]
114
+ # : (_JobInterface, Task, String) -> Hash[Symbol, untyped]
115
+ private def self.build_task_skip_payload: (_JobInterface, Task, String) -> Hash[Symbol, untyped]
116
116
 
117
- # : (DSL, Task, Integer) -> Hash[Symbol, untyped]
118
- private def self.build_task_enqueue_payload: (DSL, Task, Integer) -> Hash[Symbol, untyped]
117
+ # : (_JobInterface, Task, Integer) -> Hash[Symbol, untyped]
118
+ private def self.build_task_enqueue_payload: (_JobInterface, Task, Integer) -> Hash[Symbol, untyped]
119
119
 
120
120
  # : (Task, Context, String, Integer, Float, StandardError) -> Hash[Symbol, untyped]
121
121
  private def self.build_task_retry_payload: (Task, Context, String, Integer, Float, StandardError) -> Hash[Symbol, untyped]
122
122
 
123
- # : (DSL, Task) -> Hash[Symbol, untyped]
124
- private def self.build_dependent_payload: (DSL, Task) -> Hash[Symbol, untyped]
123
+ # : (_JobInterface, Task) -> Hash[Symbol, untyped]
124
+ private def self.build_dependent_payload: (_JobInterface, Task) -> Hash[Symbol, untyped]
125
125
 
126
- # : (DSL, Task, Numeric, Integer) -> Hash[Symbol, untyped]
127
- private def self.build_dependent_reschedule_payload: (DSL, Task, Numeric, Integer) -> Hash[Symbol, untyped]
126
+ # : (_JobInterface, Task, Numeric, Integer) -> Hash[Symbol, untyped]
127
+ private def self.build_dependent_reschedule_payload: (_JobInterface, Task, Numeric, Integer) -> Hash[Symbol, untyped]
128
128
 
129
129
  # : (Semaphore) -> Hash[Symbol, untyped]
130
130
  private def self.build_throttle_payload: (Semaphore) -> Hash[Symbol, untyped]
@@ -132,7 +132,7 @@ module JobWorkflow
132
132
  # : (String) -> Hash[Symbol, untyped]
133
133
  private def self.build_queue_payload: (String) -> Hash[Symbol, untyped]
134
134
 
135
- # : (DSL, Context, Symbol?, Integer, bool) -> Hash[Symbol, untyped]
136
- private def self.build_skip_in_dry_run_payload: (DSL, Context, Symbol?, Integer, bool) -> Hash[Symbol, untyped]
135
+ # : (_JobInterface, Context, Symbol?, Integer, bool) -> Hash[Symbol, untyped]
136
+ private def self.build_skip_in_dry_run_payload: (_JobInterface, Context, Symbol?, Integer, bool) -> Hash[Symbol, untyped]
137
137
  end
138
138
  end
@@ -33,12 +33,15 @@ module JobWorkflow
33
33
  # : (TaskJobStatus) -> void
34
34
  def update_task_job_status: (TaskJobStatus) -> void
35
35
 
36
- # : (task_name: Symbol, jobs: Array[DSL]) -> void
37
- def update_task_job_statuses_from_jobs: (task_name: Symbol, jobs: Array[DSL]) -> void
36
+ # : (task_name: Symbol, jobs: Array[_JobInterface]) -> void
37
+ def update_task_job_statuses_from_jobs: (task_name: Symbol, jobs: Array[_JobInterface]) -> void
38
38
 
39
39
  # : (Symbol) -> void
40
40
  def update_task_job_statuses_from_db: (Symbol) -> void
41
41
 
42
+ # : () -> void
43
+ def refresh_from_db!: () -> void
44
+
42
45
  private
43
46
 
44
47
  attr_accessor task_job_statuses: Hash[Symbol, Array[TaskJobStatus]]
@@ -0,0 +1,80 @@
1
+ # Generated from lib/job_workflow/monitoring/dag_layout.rb with RBS::Inline
2
+
3
+ module JobWorkflow
4
+ module Monitoring
5
+ class DagLayout
6
+ NODE_WIDTH: ::Integer
7
+
8
+ NODE_HEIGHT: ::Integer
9
+
10
+ COLUMN_GAP: ::Integer
11
+
12
+ ROW_GAP: ::Integer
13
+
14
+ PADDING: ::Integer
15
+
16
+ LABEL_LIMIT: ::Integer
17
+
18
+ # : (tasks: Array[Hash[Symbol, untyped]]) -> void
19
+ def initialize: (tasks: Array[Hash[Symbol, untyped]]) -> void
20
+
21
+ # : () -> Hash[Symbol, untyped]
22
+ def to_h: () -> Hash[Symbol, untyped]
23
+
24
+ private
25
+
26
+ attr_reader tasks: Array[Hash[Symbol, untyped]]
27
+
28
+ # : (Array[Hash[Symbol, untyped]]) -> void
29
+ def validate_tasks!: (Array[Hash[Symbol, untyped]]) -> void
30
+
31
+ # : (Hash[Symbol, untyped], Hash[Symbol, bool]) -> void
32
+ def validate_dependencies!: (Hash[Symbol, untyped], Hash[Symbol, bool]) -> void
33
+
34
+ # : () -> Array[Hash[Symbol, untyped]]
35
+ def nodes: () -> Array[Hash[Symbol, untyped]]
36
+
37
+ # : () -> Array[Hash[Symbol, untyped]]
38
+ def edges: () -> Array[Hash[Symbol, untyped]]
39
+
40
+ # : () -> Hash[Symbol, Hash[Symbol, Integer]]
41
+ def node_positions: () -> Hash[Symbol, Hash[Symbol, Integer]]
42
+
43
+ # : (Hash[Symbol, untyped], Hash[Symbol, Hash[Symbol, Integer]]) -> Integer
44
+ def dependency_column: (Hash[Symbol, untyped], Hash[Symbol, Hash[Symbol, Integer]]) -> Integer
45
+
46
+ # : (Symbol, Symbol) -> Hash[Symbol, untyped]
47
+ def edge_view: (Symbol, Symbol) -> Hash[Symbol, untyped]
48
+
49
+ # : (Hash[Symbol, untyped], Hash[Symbol, untyped]) -> String
50
+ def edge_path: (Hash[Symbol, untyped], Hash[Symbol, untyped]) -> String
51
+
52
+ # : (Symbol) -> Hash[Symbol, untyped]
53
+ def node_view: (Symbol) -> Hash[Symbol, untyped]
54
+
55
+ # : () -> Integer
56
+ def canvas_width: () -> Integer
57
+
58
+ # : () -> Integer
59
+ def canvas_height: () -> Integer
60
+
61
+ # : (Integer) -> Integer
62
+ def x_for: (Integer) -> Integer
63
+
64
+ # : (Integer) -> Integer
65
+ def y_for: (Integer) -> Integer
66
+
67
+ # : (Symbol) -> String
68
+ def truncate_label: (Symbol) -> String
69
+
70
+ # : (Hash[Symbol, untyped]) -> String?
71
+ def node_meta_label: (Hash[Symbol, untyped]) -> String?
72
+
73
+ # : () -> String
74
+ def root_task_label: () -> String
75
+
76
+ # : (Hash[Symbol, Integer]) -> String
77
+ def each_progress_label: (Hash[Symbol, Integer]) -> String
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,8 @@
1
+ # Generated from lib/job_workflow/monitoring/engine.rb with RBS::Inline
2
+
3
+ module JobWorkflow
4
+ module Monitoring
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ # Generated from lib/job_workflow/monitoring/execution_page.rb with RBS::Inline
2
+
3
+ module JobWorkflow
4
+ module Monitoring
5
+ class ExecutionPage
6
+ attr_reader executions: Array[ExecutionViewModel]
7
+
8
+ attr_reader next_cursor: String?
9
+
10
+ # : (executions: Array[ExecutionViewModel], next_cursor: String?) -> void
11
+ def initialize: (executions: Array[ExecutionViewModel], next_cursor: String?) -> void
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ # Generated from lib/job_workflow/monitoring/execution_registry.rb with RBS::Inline
2
+
3
+ module JobWorkflow
4
+ module Monitoring
5
+ class ExecutionRegistry
6
+ DEFAULT_LIMIT: ::Integer
7
+
8
+ # : (job_class_name: String, ?limit: Integer, ?cursor: String?) -> ExecutionPage
9
+ def self.page_for: (job_class_name: String, ?limit: Integer, ?cursor: String?) -> ExecutionPage
10
+
11
+ # : (String) -> ExecutionViewModel?
12
+ def self.find: (String) -> ExecutionViewModel?
13
+
14
+ # : (Hash[String, untyped], ?hydrate_sub_tasks: bool) -> ExecutionViewModel?
15
+ private def self.build_view_model: (Hash[String, untyped], ?hydrate_sub_tasks: bool) -> ExecutionViewModel?
16
+
17
+ # : (WorkflowStatus) -> void
18
+ private def self.hydrate_sub_task_state: (WorkflowStatus) -> void
19
+ end
20
+ end
21
+ end