cmdx 1.9.0 → 1.9.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.
- checksums.yaml +4 -4
- data/.cursor/prompts/yardoc.md +1 -0
- data/CHANGELOG.md +6 -0
- data/LLM.md +9 -0
- data/README.md +6 -1
- data/docs/getting_started.md +9 -0
- data/docs/index.md +13 -1
- data/lib/cmdx/attribute.rb +82 -1
- data/lib/cmdx/attribute_registry.rb +20 -0
- data/lib/cmdx/attribute_value.rb +25 -0
- data/lib/cmdx/callback_registry.rb +19 -0
- data/lib/cmdx/chain.rb +34 -1
- data/lib/cmdx/coercion_registry.rb +18 -0
- data/lib/cmdx/coercions/array.rb +2 -0
- data/lib/cmdx/coercions/big_decimal.rb +3 -0
- data/lib/cmdx/coercions/boolean.rb +5 -0
- data/lib/cmdx/coercions/complex.rb +2 -0
- data/lib/cmdx/coercions/date.rb +4 -0
- data/lib/cmdx/coercions/date_time.rb +5 -0
- data/lib/cmdx/coercions/float.rb +2 -0
- data/lib/cmdx/coercions/hash.rb +2 -0
- data/lib/cmdx/coercions/integer.rb +2 -0
- data/lib/cmdx/coercions/rational.rb +2 -0
- data/lib/cmdx/coercions/string.rb +2 -0
- data/lib/cmdx/coercions/symbol.rb +2 -0
- data/lib/cmdx/coercions/time.rb +5 -0
- data/lib/cmdx/configuration.rb +111 -3
- data/lib/cmdx/context.rb +36 -0
- data/lib/cmdx/deprecator.rb +3 -0
- data/lib/cmdx/errors.rb +22 -0
- data/lib/cmdx/executor.rb +43 -0
- data/lib/cmdx/faults.rb +14 -0
- data/lib/cmdx/identifier.rb +2 -0
- data/lib/cmdx/locale.rb +3 -0
- data/lib/cmdx/log_formatters/json.rb +2 -0
- data/lib/cmdx/log_formatters/key_value.rb +2 -0
- data/lib/cmdx/log_formatters/line.rb +2 -0
- data/lib/cmdx/log_formatters/logstash.rb +2 -0
- data/lib/cmdx/log_formatters/raw.rb +2 -0
- data/lib/cmdx/middleware_registry.rb +20 -0
- data/lib/cmdx/middlewares/correlate.rb +11 -0
- data/lib/cmdx/middlewares/runtime.rb +4 -0
- data/lib/cmdx/middlewares/timeout.rb +4 -0
- data/lib/cmdx/pipeline.rb +20 -1
- data/lib/cmdx/railtie.rb +4 -0
- data/lib/cmdx/result.rb +123 -1
- data/lib/cmdx/task.rb +91 -1
- data/lib/cmdx/utils/call.rb +2 -0
- data/lib/cmdx/utils/condition.rb +3 -0
- data/lib/cmdx/utils/format.rb +5 -0
- data/lib/cmdx/validator_registry.rb +18 -0
- data/lib/cmdx/validators/exclusion.rb +2 -0
- data/lib/cmdx/validators/format.rb +2 -0
- data/lib/cmdx/validators/inclusion.rb +2 -0
- data/lib/cmdx/validators/length.rb +14 -0
- data/lib/cmdx/validators/numeric.rb +14 -0
- data/lib/cmdx/validators/presence.rb +2 -0
- data/lib/cmdx/version.rb +4 -1
- data/lib/cmdx/workflow.rb +10 -0
- data/lib/cmdx.rb +8 -0
- data/lib/generators/cmdx/locale_generator.rb +0 -1
- metadata +1 -1
data/lib/cmdx/executor.rb
CHANGED
|
@@ -8,6 +8,14 @@ module CMDx
|
|
|
8
8
|
# and proper error handling for different types of failures.
|
|
9
9
|
class Executor
|
|
10
10
|
|
|
11
|
+
# Returns the task being executed.
|
|
12
|
+
#
|
|
13
|
+
# @return [Task] The task instance
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# executor.task.id # => "abc123"
|
|
17
|
+
#
|
|
18
|
+
# @rbs @task: Task
|
|
11
19
|
attr_reader :task
|
|
12
20
|
|
|
13
21
|
# @param task [CMDx::Task] The task to execute
|
|
@@ -16,6 +24,8 @@ module CMDx
|
|
|
16
24
|
#
|
|
17
25
|
# @example
|
|
18
26
|
# executor = CMDx::Executor.new(my_task)
|
|
27
|
+
#
|
|
28
|
+
# @rbs (Task task) -> void
|
|
19
29
|
def initialize(task)
|
|
20
30
|
@task = task
|
|
21
31
|
end
|
|
@@ -32,6 +42,8 @@ module CMDx
|
|
|
32
42
|
# @example
|
|
33
43
|
# CMDx::Executor.execute(my_task)
|
|
34
44
|
# CMDx::Executor.execute(my_task, raise: true)
|
|
45
|
+
#
|
|
46
|
+
# @rbs (Task task, raise: bool) -> Result
|
|
35
47
|
def self.execute(task, raise: false)
|
|
36
48
|
instance = new(task)
|
|
37
49
|
raise ? instance.execute! : instance.execute
|
|
@@ -44,6 +56,8 @@ module CMDx
|
|
|
44
56
|
# @example
|
|
45
57
|
# executor = CMDx::Executor.new(my_task)
|
|
46
58
|
# result = executor.execute
|
|
59
|
+
#
|
|
60
|
+
# @rbs () -> Result
|
|
47
61
|
def execute
|
|
48
62
|
task.class.settings[:middlewares].call!(task) do
|
|
49
63
|
pre_execution! unless @pre_execution
|
|
@@ -73,6 +87,8 @@ module CMDx
|
|
|
73
87
|
# @example
|
|
74
88
|
# executor = CMDx::Executor.new(my_task)
|
|
75
89
|
# result = executor.execute!
|
|
90
|
+
#
|
|
91
|
+
# @rbs () -> Result
|
|
76
92
|
def execute!
|
|
77
93
|
task.class.settings[:middlewares].call!(task) do
|
|
78
94
|
pre_execution! unless @pre_execution
|
|
@@ -104,6 +120,8 @@ module CMDx
|
|
|
104
120
|
#
|
|
105
121
|
# @example
|
|
106
122
|
# halt_execution?(fault_exception)
|
|
123
|
+
#
|
|
124
|
+
# @rbs (Exception exception) -> bool
|
|
107
125
|
def halt_execution?(exception)
|
|
108
126
|
breakpoints = task.class.settings[:breakpoints] || task.class.settings[:task_breakpoints]
|
|
109
127
|
breakpoints = Array(breakpoints).map(&:to_s).uniq
|
|
@@ -119,6 +137,8 @@ module CMDx
|
|
|
119
137
|
#
|
|
120
138
|
# @example
|
|
121
139
|
# retry_execution?(standard_error)
|
|
140
|
+
#
|
|
141
|
+
# @rbs (Exception exception) -> bool
|
|
122
142
|
def retry_execution?(exception)
|
|
123
143
|
available_retries = (task.class.settings[:retries] || 0).to_i
|
|
124
144
|
return false unless available_retries.positive?
|
|
@@ -151,6 +171,8 @@ module CMDx
|
|
|
151
171
|
#
|
|
152
172
|
# @example
|
|
153
173
|
# raise_exception(standard_error)
|
|
174
|
+
#
|
|
175
|
+
# @rbs (Exception exception) -> void
|
|
154
176
|
def raise_exception(exception)
|
|
155
177
|
Chain.clear
|
|
156
178
|
|
|
@@ -165,6 +187,8 @@ module CMDx
|
|
|
165
187
|
#
|
|
166
188
|
# @example
|
|
167
189
|
# invoke_callbacks(:before_execution)
|
|
190
|
+
#
|
|
191
|
+
# @rbs (Symbol type) -> void
|
|
168
192
|
def invoke_callbacks(type)
|
|
169
193
|
task.class.settings[:callbacks].invoke(type, task)
|
|
170
194
|
end
|
|
@@ -172,11 +196,15 @@ module CMDx
|
|
|
172
196
|
private
|
|
173
197
|
|
|
174
198
|
# Lazy loaded repeator instance to handle retries.
|
|
199
|
+
#
|
|
200
|
+
# @rbs () -> untyped
|
|
175
201
|
def repeator
|
|
176
202
|
@repeator ||= Repeator.new(task)
|
|
177
203
|
end
|
|
178
204
|
|
|
179
205
|
# Performs pre-execution tasks including validation and attribute verification.
|
|
206
|
+
#
|
|
207
|
+
# @rbs () -> void
|
|
180
208
|
def pre_execution!
|
|
181
209
|
@pre_execution = true
|
|
182
210
|
|
|
@@ -195,6 +223,8 @@ module CMDx
|
|
|
195
223
|
end
|
|
196
224
|
|
|
197
225
|
# Executes the main task logic.
|
|
226
|
+
#
|
|
227
|
+
# @rbs () -> void
|
|
198
228
|
def execution!
|
|
199
229
|
invoke_callbacks(:before_execution)
|
|
200
230
|
|
|
@@ -203,6 +233,8 @@ module CMDx
|
|
|
203
233
|
end
|
|
204
234
|
|
|
205
235
|
# Performs post-execution tasks including callback invocation.
|
|
236
|
+
#
|
|
237
|
+
# @rbs () -> void
|
|
206
238
|
def post_execution!
|
|
207
239
|
invoke_callbacks(:"on_#{task.result.state}")
|
|
208
240
|
invoke_callbacks(:on_executed) if task.result.executed?
|
|
@@ -213,6 +245,8 @@ module CMDx
|
|
|
213
245
|
end
|
|
214
246
|
|
|
215
247
|
# Finalizes execution by freezing the task and logging results.
|
|
248
|
+
#
|
|
249
|
+
# @rbs () -> Result
|
|
216
250
|
def finalize_execution!
|
|
217
251
|
log_execution!
|
|
218
252
|
log_backtrace! if task.class.settings[:backtrace]
|
|
@@ -222,11 +256,15 @@ module CMDx
|
|
|
222
256
|
end
|
|
223
257
|
|
|
224
258
|
# Logs the execution result at the configured log level.
|
|
259
|
+
#
|
|
260
|
+
# @rbs () -> void
|
|
225
261
|
def log_execution!
|
|
226
262
|
task.logger.info { task.result.to_h }
|
|
227
263
|
end
|
|
228
264
|
|
|
229
265
|
# Logs the backtrace of the exception if the task failed.
|
|
266
|
+
#
|
|
267
|
+
# @rbs () -> void
|
|
230
268
|
def log_backtrace!
|
|
231
269
|
return unless task.result.failed?
|
|
232
270
|
|
|
@@ -244,6 +282,8 @@ module CMDx
|
|
|
244
282
|
end
|
|
245
283
|
|
|
246
284
|
# Freezes the task and its associated objects to prevent modifications.
|
|
285
|
+
#
|
|
286
|
+
# @rbs () -> void
|
|
247
287
|
def freeze_execution!
|
|
248
288
|
# Stubbing on frozen objects is not allowed in most test environments.
|
|
249
289
|
skip_freezing = ENV.fetch("SKIP_CMDX_FREEZING", false)
|
|
@@ -260,6 +300,9 @@ module CMDx
|
|
|
260
300
|
task.chain.freeze
|
|
261
301
|
end
|
|
262
302
|
|
|
303
|
+
# Clears the chain if the task is the outermost (top-level) task.
|
|
304
|
+
#
|
|
305
|
+
# @rbs () -> void
|
|
263
306
|
def clear_chain!
|
|
264
307
|
return unless task.result.index.zero?
|
|
265
308
|
|
data/lib/cmdx/faults.rb
CHANGED
|
@@ -11,6 +11,14 @@ module CMDx
|
|
|
11
11
|
|
|
12
12
|
extend Forwardable
|
|
13
13
|
|
|
14
|
+
# Returns the result that caused this fault.
|
|
15
|
+
#
|
|
16
|
+
# @return [Result] The result instance
|
|
17
|
+
#
|
|
18
|
+
# @example
|
|
19
|
+
# fault.result.reason # => "Validation failed"
|
|
20
|
+
#
|
|
21
|
+
# @rbs @result: Result
|
|
14
22
|
attr_reader :result
|
|
15
23
|
|
|
16
24
|
def_delegators :result, :task, :context, :chain
|
|
@@ -24,6 +32,8 @@ module CMDx
|
|
|
24
32
|
# @example
|
|
25
33
|
# fault = Fault.new(task_result)
|
|
26
34
|
# fault.result.reason # => "Task validation failed"
|
|
35
|
+
#
|
|
36
|
+
# @rbs (Result result) -> void
|
|
27
37
|
def initialize(result)
|
|
28
38
|
@result = result
|
|
29
39
|
|
|
@@ -41,6 +51,8 @@ module CMDx
|
|
|
41
51
|
# @example
|
|
42
52
|
# Fault.for?(UserTask, AdminUserTask)
|
|
43
53
|
# # => true if fault.task is a UserTask or AdminUserTask
|
|
54
|
+
#
|
|
55
|
+
# @rbs (*Class tasks) -> Class
|
|
44
56
|
def for?(*tasks)
|
|
45
57
|
temp_fault = Class.new(self) do
|
|
46
58
|
def self.===(other)
|
|
@@ -62,6 +74,8 @@ module CMDx
|
|
|
62
74
|
# @example
|
|
63
75
|
# Fault.matches? { |fault| fault.result.metadata[:critical] }
|
|
64
76
|
# # => true if fault has critical metadata
|
|
77
|
+
#
|
|
78
|
+
# @rbs () { (Fault) -> bool } -> Class
|
|
65
79
|
def matches?(&block)
|
|
66
80
|
raise ArgumentError, "block required" unless block_given?
|
|
67
81
|
|
data/lib/cmdx/identifier.rb
CHANGED
data/lib/cmdx/locale.rb
CHANGED
|
@@ -8,6 +8,7 @@ module CMDx
|
|
|
8
8
|
|
|
9
9
|
extend self
|
|
10
10
|
|
|
11
|
+
# @rbs EN: Hash[String, untyped]
|
|
11
12
|
EN = YAML.load_file(CMDx.gem_path.join("lib/locales/en.yml")).freeze
|
|
12
13
|
private_constant :EN
|
|
13
14
|
|
|
@@ -34,6 +35,8 @@ module CMDx
|
|
|
34
35
|
# @example With fallback
|
|
35
36
|
# Locale.translate("missing.key", default: "Custom fallback message")
|
|
36
37
|
# # => "Custom fallback message"
|
|
38
|
+
#
|
|
39
|
+
# @rbs ((String | Symbol) key, **untyped options) -> String
|
|
37
40
|
def translate(key, **options)
|
|
38
41
|
options[:default] ||= EN.dig("en", *key.to_s.split("."))
|
|
39
42
|
return ::I18n.t(key, **options) if defined?(::I18n)
|
|
@@ -21,6 +21,8 @@ module CMDx
|
|
|
21
21
|
# @example Basic usage
|
|
22
22
|
# logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
|
|
23
23
|
# # => '{"severity":"INFO","timestamp":"2024-01-15T10:30:45.123456Z","progname":"MyApp","pid":12345,"message":"User logged in"}\n'
|
|
24
|
+
#
|
|
25
|
+
# @rbs (String severity, Time time, String? progname, String message) -> String
|
|
24
26
|
def call(severity, time, progname, message)
|
|
25
27
|
hash = {
|
|
26
28
|
severity:,
|
|
@@ -21,6 +21,8 @@ module CMDx
|
|
|
21
21
|
# @example Basic usage
|
|
22
22
|
# logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
|
|
23
23
|
# # => "severity=INFO timestamp=2024-01-15T10:30:45.123456Z progname=MyApp pid=12345 message=User logged in\n"
|
|
24
|
+
#
|
|
25
|
+
# @rbs (String severity, Time time, String? progname, String message) -> String
|
|
24
26
|
def call(severity, time, progname, message)
|
|
25
27
|
hash = {
|
|
26
28
|
severity:,
|
|
@@ -21,6 +21,8 @@ module CMDx
|
|
|
21
21
|
# @example Basic usage
|
|
22
22
|
# logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
|
|
23
23
|
# # => "I, [2024-01-15T10:30:45.123456Z #12345] INFO -- MyApp: User logged in\n"
|
|
24
|
+
#
|
|
25
|
+
# @rbs (String severity, Time time, String? progname, String message) -> String
|
|
24
26
|
def call(severity, time, progname, message)
|
|
25
27
|
"#{severity[0]}, [#{time.utc.iso8601(6)} ##{Process.pid}] #{severity} -- #{progname}: #{message}\n"
|
|
26
28
|
end
|
|
@@ -22,6 +22,8 @@ module CMDx
|
|
|
22
22
|
# @example Basic usage
|
|
23
23
|
# logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
|
|
24
24
|
# # => '{"severity":"INFO","progname":"MyApp","pid":12345,"message":"User logged in","@version":"1","@timestamp":"2024-01-15T10:30:45.123456Z"}\n'
|
|
25
|
+
#
|
|
26
|
+
# @rbs (String severity, Time time, String? progname, String message) -> String
|
|
25
27
|
def call(severity, time, progname, message)
|
|
26
28
|
hash = {
|
|
27
29
|
severity:,
|
|
@@ -22,6 +22,8 @@ module CMDx
|
|
|
22
22
|
# @example Basic usage
|
|
23
23
|
# logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
|
|
24
24
|
# # => "User logged in\n"
|
|
25
|
+
#
|
|
26
|
+
# @rbs (String severity, Time time, String? progname, String message) -> String
|
|
25
27
|
def call(severity, time, progname, message)
|
|
26
28
|
"#{message}\n"
|
|
27
29
|
end
|
|
@@ -9,6 +9,14 @@ module CMDx
|
|
|
9
9
|
# they were registered.
|
|
10
10
|
class MiddlewareRegistry
|
|
11
11
|
|
|
12
|
+
# Returns the ordered collection of middleware entries.
|
|
13
|
+
#
|
|
14
|
+
# @return [Array<Array>] Array of middleware-options pairs
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# registry.registry # => [[LoggingMiddleware, {level: :debug}], [AuthMiddleware, {}]]
|
|
18
|
+
#
|
|
19
|
+
# @rbs @registry: Array[Array[untyped]]
|
|
12
20
|
attr_reader :registry
|
|
13
21
|
alias to_a registry
|
|
14
22
|
|
|
@@ -19,6 +27,8 @@ module CMDx
|
|
|
19
27
|
# @example
|
|
20
28
|
# registry = MiddlewareRegistry.new
|
|
21
29
|
# registry = MiddlewareRegistry.new([[MyMiddleware, {option: 'value'}]])
|
|
30
|
+
#
|
|
31
|
+
# @rbs (?Array[Array[untyped]] registry) -> void
|
|
22
32
|
def initialize(registry = [])
|
|
23
33
|
@registry = registry
|
|
24
34
|
end
|
|
@@ -29,6 +39,8 @@ module CMDx
|
|
|
29
39
|
#
|
|
30
40
|
# @example
|
|
31
41
|
# new_registry = registry.dup
|
|
42
|
+
#
|
|
43
|
+
# @rbs () -> MiddlewareRegistry
|
|
32
44
|
def dup
|
|
33
45
|
self.class.new(registry.map(&:dup))
|
|
34
46
|
end
|
|
@@ -46,6 +58,8 @@ module CMDx
|
|
|
46
58
|
# @example
|
|
47
59
|
# registry.register(LoggingMiddleware, at: 0, log_level: :debug)
|
|
48
60
|
# registry.register(AuthMiddleware, at: -1, timeout: 30)
|
|
61
|
+
#
|
|
62
|
+
# @rbs (untyped middleware, ?at: Integer, **untyped options) -> self
|
|
49
63
|
def register(middleware, at: -1, **options)
|
|
50
64
|
registry.insert(at, [middleware, options])
|
|
51
65
|
self
|
|
@@ -59,6 +73,8 @@ module CMDx
|
|
|
59
73
|
#
|
|
60
74
|
# @example
|
|
61
75
|
# registry.deregister(LoggingMiddleware)
|
|
76
|
+
#
|
|
77
|
+
# @rbs (untyped middleware) -> self
|
|
62
78
|
def deregister(middleware)
|
|
63
79
|
registry.reject! { |mw, _opts| mw == middleware }
|
|
64
80
|
self
|
|
@@ -79,6 +95,8 @@ module CMDx
|
|
|
79
95
|
# result = registry.call!(my_task) do |processed_task|
|
|
80
96
|
# processed_task.execute
|
|
81
97
|
# end
|
|
98
|
+
#
|
|
99
|
+
# @rbs (untyped task) { (untyped) -> untyped } -> untyped
|
|
82
100
|
def call!(task, &)
|
|
83
101
|
raise ArgumentError, "block required" unless block_given?
|
|
84
102
|
|
|
@@ -96,6 +114,8 @@ module CMDx
|
|
|
96
114
|
# @yieldparam task [Object] The processed task object
|
|
97
115
|
#
|
|
98
116
|
# @return [Object] Result of the block execution or next middleware call
|
|
117
|
+
#
|
|
118
|
+
# @rbs (Integer index, untyped task) { (untyped) -> untyped } -> untyped
|
|
99
119
|
def recursively_call_middleware(index, task, &block)
|
|
100
120
|
return yield(task) if index >= registry.size
|
|
101
121
|
|
|
@@ -12,6 +12,7 @@ module CMDx
|
|
|
12
12
|
|
|
13
13
|
extend self
|
|
14
14
|
|
|
15
|
+
# @rbs THREAD_KEY: Symbol
|
|
15
16
|
THREAD_KEY = :cmdx_correlate
|
|
16
17
|
|
|
17
18
|
# Retrieves the current correlation ID from thread-local storage.
|
|
@@ -20,6 +21,8 @@ module CMDx
|
|
|
20
21
|
#
|
|
21
22
|
# @example Get current correlation ID
|
|
22
23
|
# Correlate.id # => "550e8400-e29b-41d4-a716-446655440000"
|
|
24
|
+
#
|
|
25
|
+
# @rbs () -> String?
|
|
23
26
|
def id
|
|
24
27
|
Thread.current[THREAD_KEY]
|
|
25
28
|
end
|
|
@@ -31,6 +34,8 @@ module CMDx
|
|
|
31
34
|
#
|
|
32
35
|
# @example Set correlation ID
|
|
33
36
|
# Correlate.id = "abc-123-def"
|
|
37
|
+
#
|
|
38
|
+
# @rbs (String id) -> String
|
|
34
39
|
def id=(id)
|
|
35
40
|
Thread.current[THREAD_KEY] = id
|
|
36
41
|
end
|
|
@@ -41,6 +46,8 @@ module CMDx
|
|
|
41
46
|
#
|
|
42
47
|
# @example Clear correlation ID
|
|
43
48
|
# Correlate.clear
|
|
49
|
+
#
|
|
50
|
+
# @rbs () -> nil
|
|
44
51
|
def clear
|
|
45
52
|
Thread.current[THREAD_KEY] = nil
|
|
46
53
|
end
|
|
@@ -58,6 +65,8 @@ module CMDx
|
|
|
58
65
|
# perform_operation
|
|
59
66
|
# end
|
|
60
67
|
# # Previous ID is restored
|
|
68
|
+
#
|
|
69
|
+
# @rbs (String new_id) { () -> untyped } -> untyped
|
|
61
70
|
def use(new_id)
|
|
62
71
|
old_id = id
|
|
63
72
|
self.id = new_id
|
|
@@ -92,6 +101,8 @@ module CMDx
|
|
|
92
101
|
# Correlate.call(task, id: -> { "dynamic-#{Time.now.to_i}" }, &block)
|
|
93
102
|
# @example Conditional correlation
|
|
94
103
|
# Correlate.call(task, if: :enable_correlation, &block)
|
|
104
|
+
#
|
|
105
|
+
# @rbs (Task task, **untyped options) { () -> untyped } -> untyped
|
|
95
106
|
def call(task, **options, &)
|
|
96
107
|
return yield unless Utils::Condition.evaluate(task, options)
|
|
97
108
|
|
|
@@ -32,6 +32,8 @@ module CMDx
|
|
|
32
32
|
# Runtime.call(task, if: :enable_profiling, &block)
|
|
33
33
|
# @example Disable runtime measurement
|
|
34
34
|
# Runtime.call(task, unless: :skip_profiling, &block)
|
|
35
|
+
#
|
|
36
|
+
# @rbs (Task task, **untyped options) { () -> untyped } -> untyped
|
|
35
37
|
def call(task, **options)
|
|
36
38
|
return yield unless Utils::Condition.evaluate(task, options)
|
|
37
39
|
|
|
@@ -49,6 +51,8 @@ module CMDx
|
|
|
49
51
|
# timing measurements that are not affected by system clock changes.
|
|
50
52
|
#
|
|
51
53
|
# @return [Integer] Current monotonic time in milliseconds
|
|
54
|
+
#
|
|
55
|
+
# @rbs () -> Integer
|
|
52
56
|
def monotonic_time
|
|
53
57
|
Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
|
54
58
|
end
|
|
@@ -21,6 +21,8 @@ module CMDx
|
|
|
21
21
|
extend self
|
|
22
22
|
|
|
23
23
|
# Default timeout limit in seconds when none is specified.
|
|
24
|
+
#
|
|
25
|
+
# @rbs DEFAULT_LIMIT: Integer
|
|
24
26
|
DEFAULT_LIMIT = 3
|
|
25
27
|
|
|
26
28
|
# Middleware entry point that enforces execution time limits.
|
|
@@ -51,6 +53,8 @@ module CMDx
|
|
|
51
53
|
# Timeout.call(task, seconds: -> { calculate_timeout }, &block)
|
|
52
54
|
# @example Conditional timeout control
|
|
53
55
|
# Timeout.call(task, if: :enable_timeout, &block)
|
|
56
|
+
#
|
|
57
|
+
# @rbs (Task task, **untyped options) { () -> untyped } -> untyped
|
|
54
58
|
def call(task, **options, &)
|
|
55
59
|
return yield unless Utils::Condition.evaluate(task, options)
|
|
56
60
|
|
data/lib/cmdx/pipeline.rb
CHANGED
|
@@ -6,7 +6,14 @@ module CMDx
|
|
|
6
6
|
# and handling breakpoints that can interrupt execution at specific task statuses.
|
|
7
7
|
class Pipeline
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# Returns the workflow being executed by this pipeline.
|
|
10
|
+
#
|
|
11
|
+
# @return [Workflow] The workflow instance
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# pipeline.workflow.context[:status] # => "processing"
|
|
15
|
+
#
|
|
16
|
+
# @rbs @workflow: Workflow
|
|
10
17
|
attr_reader :workflow
|
|
11
18
|
|
|
12
19
|
# @param workflow [Workflow] The workflow to execute
|
|
@@ -15,6 +22,8 @@ module CMDx
|
|
|
15
22
|
#
|
|
16
23
|
# @example
|
|
17
24
|
# pipeline = Pipeline.new(my_workflow)
|
|
25
|
+
#
|
|
26
|
+
# @rbs (Workflow workflow) -> void
|
|
18
27
|
def initialize(workflow)
|
|
19
28
|
@workflow = workflow
|
|
20
29
|
end
|
|
@@ -27,6 +36,8 @@ module CMDx
|
|
|
27
36
|
#
|
|
28
37
|
# @example
|
|
29
38
|
# Pipeline.execute(my_workflow)
|
|
39
|
+
#
|
|
40
|
+
# @rbs (Workflow workflow) -> void
|
|
30
41
|
def self.execute(workflow)
|
|
31
42
|
new(workflow).execute
|
|
32
43
|
end
|
|
@@ -40,6 +51,8 @@ module CMDx
|
|
|
40
51
|
# @example
|
|
41
52
|
# pipeline = Pipeline.new(my_workflow)
|
|
42
53
|
# pipeline.execute
|
|
54
|
+
#
|
|
55
|
+
# @rbs () -> void
|
|
43
56
|
def execute
|
|
44
57
|
workflow.class.pipeline.each do |group|
|
|
45
58
|
next unless Utils::Condition.evaluate(workflow, group.options)
|
|
@@ -65,6 +78,8 @@ module CMDx
|
|
|
65
78
|
#
|
|
66
79
|
# @example
|
|
67
80
|
# execute_group_tasks(group, ["failed", "skipped"])
|
|
81
|
+
#
|
|
82
|
+
# @rbs (untyped group, Array[String] breakpoints) -> void
|
|
68
83
|
def execute_group_tasks(group, breakpoints)
|
|
69
84
|
case strategy = group.options[:strategy]
|
|
70
85
|
when NilClass, /sequential/ then execute_tasks_in_sequence(group, breakpoints)
|
|
@@ -85,6 +100,8 @@ module CMDx
|
|
|
85
100
|
#
|
|
86
101
|
# @example
|
|
87
102
|
# execute_tasks_in_sequence(group, ["failed", "skipped"])
|
|
103
|
+
#
|
|
104
|
+
# @rbs (untyped group, Array[String] breakpoints) -> void
|
|
88
105
|
def execute_tasks_in_sequence(group, breakpoints)
|
|
89
106
|
group.tasks.each do |task|
|
|
90
107
|
task_result = task.execute(workflow.context)
|
|
@@ -107,6 +124,8 @@ module CMDx
|
|
|
107
124
|
#
|
|
108
125
|
# @example
|
|
109
126
|
# execute_tasks_in_parallel(group, ["failed"])
|
|
127
|
+
#
|
|
128
|
+
# @rbs (untyped group, Array[String] breakpoints) -> void
|
|
110
129
|
def execute_tasks_in_parallel(group, breakpoints)
|
|
111
130
|
raise "install the `parallel` gem to use this feature" unless defined?(Parallel)
|
|
112
131
|
|
data/lib/cmdx/railtie.rb
CHANGED
|
@@ -21,6 +21,8 @@ module CMDx
|
|
|
21
21
|
# # This initializer runs automatically when Rails starts
|
|
22
22
|
# # It will load locales like en.yml, es.yml, fr.yml if they exist
|
|
23
23
|
# # in the CMDx gem's locales directory
|
|
24
|
+
#
|
|
25
|
+
# @rbs (untyped app) -> void
|
|
24
26
|
initializer("cmdx.configure_locales") do |app|
|
|
25
27
|
Array(app.config.i18n.available_locales).each do |locale|
|
|
26
28
|
path = CMDx.gem_path.join("lib/locales/#{locale}.yml")
|
|
@@ -35,6 +37,8 @@ module CMDx
|
|
|
35
37
|
# Configures the backtrace cleaner for CMDx in a Rails environment.
|
|
36
38
|
#
|
|
37
39
|
# Sets the backtrace cleaner to the Rails backtrace cleaner.
|
|
40
|
+
#
|
|
41
|
+
# @rbs () -> void
|
|
38
42
|
initializer("cmdx.backtrace_cleaner") do
|
|
39
43
|
CMDx.configuration.backtrace_cleaner = lambda do |backtrace|
|
|
40
44
|
Rails.backtrace_cleaner.clean(backtrace)
|