cmdx 1.21.0 → 2.0.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 +118 -1
- data/README.md +37 -24
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/callbacks.rb +179 -0
- data/lib/cmdx/chain.rb +78 -175
- data/lib/cmdx/coercions/array.rb +19 -33
- data/lib/cmdx/coercions/big_decimal.rb +12 -29
- data/lib/cmdx/coercions/boolean.rb +25 -45
- data/lib/cmdx/coercions/coerce.rb +32 -0
- data/lib/cmdx/coercions/complex.rb +12 -27
- data/lib/cmdx/coercions/date.rb +29 -33
- data/lib/cmdx/coercions/date_time.rb +29 -33
- data/lib/cmdx/coercions/float.rb +8 -29
- data/lib/cmdx/coercions/hash.rb +17 -43
- data/lib/cmdx/coercions/integer.rb +8 -32
- data/lib/cmdx/coercions/rational.rb +12 -33
- data/lib/cmdx/coercions/string.rb +6 -24
- data/lib/cmdx/coercions/symbol.rb +12 -26
- data/lib/cmdx/coercions/time.rb +31 -35
- data/lib/cmdx/coercions.rb +174 -0
- data/lib/cmdx/configuration.rb +45 -237
- data/lib/cmdx/context.rb +264 -243
- data/lib/cmdx/deprecation.rb +67 -0
- data/lib/cmdx/deprecators/error.rb +22 -0
- data/lib/cmdx/deprecators/log.rb +22 -0
- data/lib/cmdx/deprecators/warn.rb +21 -0
- data/lib/cmdx/deprecators.rb +101 -0
- data/lib/cmdx/errors.rb +145 -79
- data/lib/cmdx/executors/fiber.rb +42 -0
- data/lib/cmdx/executors/thread.rb +36 -0
- data/lib/cmdx/executors.rb +95 -0
- data/lib/cmdx/fault.rb +85 -78
- data/lib/cmdx/i18n_proxy.rb +104 -0
- data/lib/cmdx/input.rb +294 -0
- data/lib/cmdx/inputs.rb +218 -0
- data/lib/cmdx/log_formatters/json.rb +9 -20
- data/lib/cmdx/log_formatters/key_value.rb +10 -21
- data/lib/cmdx/log_formatters/line.rb +7 -19
- data/lib/cmdx/log_formatters/logstash.rb +8 -21
- data/lib/cmdx/log_formatters/raw.rb +8 -20
- data/lib/cmdx/logger_proxy.rb +30 -0
- data/lib/cmdx/mergers/deep_merge.rb +23 -0
- data/lib/cmdx/mergers/last_write_wins.rb +23 -0
- data/lib/cmdx/mergers/no_merge.rb +20 -0
- data/lib/cmdx/mergers.rb +95 -0
- data/lib/cmdx/middlewares.rb +128 -0
- data/lib/cmdx/output.rb +115 -0
- data/lib/cmdx/outputs.rb +66 -0
- data/lib/cmdx/pipeline.rb +144 -131
- data/lib/cmdx/railtie.rb +10 -36
- data/lib/cmdx/result.rb +247 -524
- data/lib/cmdx/retriers/bounded_random.rb +24 -0
- data/lib/cmdx/retriers/decorrelated_jitter.rb +28 -0
- data/lib/cmdx/retriers/exponential.rb +23 -0
- data/lib/cmdx/retriers/fibonacci.rb +39 -0
- data/lib/cmdx/retriers/full_random.rb +23 -0
- data/lib/cmdx/retriers/half_random.rb +24 -0
- data/lib/cmdx/retriers/linear.rb +23 -0
- data/lib/cmdx/retriers.rb +106 -0
- data/lib/cmdx/retry.rb +117 -138
- data/lib/cmdx/runtime.rb +251 -0
- data/lib/cmdx/settings.rb +68 -200
- data/lib/cmdx/signal.rb +165 -0
- data/lib/cmdx/task.rb +443 -343
- data/lib/cmdx/telemetry.rb +108 -0
- data/lib/cmdx/util.rb +73 -0
- data/lib/cmdx/validators/absence.rb +10 -39
- data/lib/cmdx/validators/exclusion.rb +33 -52
- data/lib/cmdx/validators/format.rb +19 -49
- data/lib/cmdx/validators/inclusion.rb +33 -54
- data/lib/cmdx/validators/length.rb +125 -127
- data/lib/cmdx/validators/numeric.rb +123 -123
- data/lib/cmdx/validators/presence.rb +10 -39
- data/lib/cmdx/validators/validate.rb +31 -0
- data/lib/cmdx/validators.rb +161 -0
- data/lib/cmdx/version.rb +2 -4
- data/lib/cmdx/workflow.rb +71 -96
- data/lib/cmdx.rb +111 -42
- data/lib/generators/cmdx/install_generator.rb +7 -17
- data/lib/generators/cmdx/task_generator.rb +12 -29
- data/lib/generators/cmdx/templates/install.rb +120 -48
- data/lib/generators/cmdx/templates/task.rb.tt +1 -1
- data/lib/generators/cmdx/templates/workflow.rb.tt +1 -2
- data/lib/generators/cmdx/workflow_generator.rb +12 -29
- data/lib/locales/en.yml +8 -7
- data/mkdocs.yml +25 -23
- metadata +39 -138
- data/lib/cmdx/attribute.rb +0 -440
- data/lib/cmdx/attribute_registry.rb +0 -185
- data/lib/cmdx/attribute_value.rb +0 -252
- data/lib/cmdx/callback_registry.rb +0 -169
- data/lib/cmdx/coercion_registry.rb +0 -138
- data/lib/cmdx/deprecator.rb +0 -77
- data/lib/cmdx/exception.rb +0 -46
- data/lib/cmdx/executor.rb +0 -378
- data/lib/cmdx/identifier.rb +0 -30
- data/lib/cmdx/locale.rb +0 -78
- data/lib/cmdx/middleware_registry.rb +0 -148
- data/lib/cmdx/middlewares/correlate.rb +0 -140
- data/lib/cmdx/middlewares/runtime.rb +0 -77
- data/lib/cmdx/middlewares/timeout.rb +0 -78
- data/lib/cmdx/parallelizer.rb +0 -100
- data/lib/cmdx/utils/call.rb +0 -53
- data/lib/cmdx/utils/condition.rb +0 -71
- data/lib/cmdx/utils/format.rb +0 -82
- data/lib/cmdx/utils/normalize.rb +0 -52
- data/lib/cmdx/utils/wrap.rb +0 -38
- data/lib/cmdx/validator_registry.rb +0 -143
- data/lib/generators/cmdx/locale_generator.rb +0 -39
- data/lib/locales/af.yml +0 -55
- data/lib/locales/ar.yml +0 -55
- data/lib/locales/az.yml +0 -55
- data/lib/locales/be.yml +0 -55
- data/lib/locales/bg.yml +0 -55
- data/lib/locales/bn.yml +0 -55
- data/lib/locales/bs.yml +0 -55
- data/lib/locales/ca.yml +0 -55
- data/lib/locales/cnr.yml +0 -55
- data/lib/locales/cs.yml +0 -55
- data/lib/locales/cy.yml +0 -55
- data/lib/locales/da.yml +0 -55
- data/lib/locales/de.yml +0 -55
- data/lib/locales/dz.yml +0 -55
- data/lib/locales/el.yml +0 -55
- data/lib/locales/eo.yml +0 -55
- data/lib/locales/es.yml +0 -55
- data/lib/locales/et.yml +0 -55
- data/lib/locales/eu.yml +0 -55
- data/lib/locales/fa.yml +0 -55
- data/lib/locales/fi.yml +0 -55
- data/lib/locales/fr.yml +0 -55
- data/lib/locales/fy.yml +0 -55
- data/lib/locales/gd.yml +0 -55
- data/lib/locales/gl.yml +0 -55
- data/lib/locales/he.yml +0 -55
- data/lib/locales/hi.yml +0 -55
- data/lib/locales/hr.yml +0 -55
- data/lib/locales/hu.yml +0 -55
- data/lib/locales/hy.yml +0 -55
- data/lib/locales/id.yml +0 -55
- data/lib/locales/is.yml +0 -55
- data/lib/locales/it.yml +0 -55
- data/lib/locales/ja.yml +0 -55
- data/lib/locales/ka.yml +0 -55
- data/lib/locales/kk.yml +0 -55
- data/lib/locales/km.yml +0 -55
- data/lib/locales/kn.yml +0 -55
- data/lib/locales/ko.yml +0 -55
- data/lib/locales/lb.yml +0 -55
- data/lib/locales/lo.yml +0 -55
- data/lib/locales/lt.yml +0 -55
- data/lib/locales/lv.yml +0 -55
- data/lib/locales/mg.yml +0 -55
- data/lib/locales/mk.yml +0 -55
- data/lib/locales/ml.yml +0 -55
- data/lib/locales/mn.yml +0 -55
- data/lib/locales/mr-IN.yml +0 -55
- data/lib/locales/ms.yml +0 -55
- data/lib/locales/nb.yml +0 -55
- data/lib/locales/ne.yml +0 -55
- data/lib/locales/nl.yml +0 -55
- data/lib/locales/nn.yml +0 -55
- data/lib/locales/oc.yml +0 -55
- data/lib/locales/or.yml +0 -55
- data/lib/locales/pa.yml +0 -55
- data/lib/locales/pl.yml +0 -55
- data/lib/locales/pt.yml +0 -55
- data/lib/locales/rm.yml +0 -55
- data/lib/locales/ro.yml +0 -55
- data/lib/locales/ru.yml +0 -55
- data/lib/locales/sc.yml +0 -55
- data/lib/locales/sk.yml +0 -55
- data/lib/locales/sl.yml +0 -55
- data/lib/locales/sq.yml +0 -55
- data/lib/locales/sr.yml +0 -55
- data/lib/locales/st.yml +0 -55
- data/lib/locales/sv.yml +0 -55
- data/lib/locales/sw.yml +0 -55
- data/lib/locales/ta.yml +0 -55
- data/lib/locales/te.yml +0 -55
- data/lib/locales/th.yml +0 -55
- data/lib/locales/tl.yml +0 -55
- data/lib/locales/tr.yml +0 -55
- data/lib/locales/tt.yml +0 -55
- data/lib/locales/ug.yml +0 -55
- data/lib/locales/uk.yml +0 -55
- data/lib/locales/ur.yml +0 -55
- data/lib/locales/uz.yml +0 -55
- data/lib/locales/vi.yml +0 -55
- data/lib/locales/wo.yml +0 -55
- data/lib/locales/zh-CN.yml +0 -55
- data/lib/locales/zh-HK.yml +0 -55
- data/lib/locales/zh-TW.yml +0 -55
- data/lib/locales/zh-YUE.yml +0 -55
data/lib/cmdx/task.rb
CHANGED
|
@@ -1,418 +1,518 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module CMDx
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
4
|
+
# Base class for all units of work. Subclasses override `#work` and
|
|
5
|
+
# declare their contract via `required`, `optional`, `output`, `callbacks`,
|
|
6
|
+
# `retry_on`, `deprecation`, and `settings`. Invoked via {.execute} (safe)
|
|
7
|
+
# or {.execute!} (strict, raises on failure).
|
|
8
|
+
#
|
|
9
|
+
# Inheritance: every registry accessor (middlewares, callbacks, coercions,
|
|
10
|
+
# validators, executors, mergers, telemetry, inputs, outputs) lazily clones from the
|
|
11
|
+
# superclass's registry (or the global configuration at the top of the
|
|
12
|
+
# hierarchy), so subclasses extend rather than replace.
|
|
13
|
+
#
|
|
14
|
+
# @see Runtime
|
|
15
|
+
# @see Workflow
|
|
7
16
|
class Task
|
|
8
17
|
|
|
9
|
-
|
|
18
|
+
class << self
|
|
10
19
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
# Declares exceptions to retry on. Builds on the superclass's `Retry`.
|
|
21
|
+
# Passing no exceptions returns the current (possibly inherited) Retry.
|
|
22
|
+
#
|
|
23
|
+
# @param exceptions [Array<Class>]
|
|
24
|
+
# @param options [Hash{Symbol => Object}] see {Retry#initialize}
|
|
25
|
+
# @option options [Integer] :limit (see {Retry#initialize})
|
|
26
|
+
# @option options [Float] :delay (see {Retry#initialize})
|
|
27
|
+
# @option options [Float] :max_delay (see {Retry#initialize})
|
|
28
|
+
# @option options [Symbol, Proc, #call] :jitter (see {Retry#initialize})
|
|
29
|
+
# @option options [Symbol, Proc, #call] :if gate `(task, error, attempt)` for retries
|
|
30
|
+
# @option options [Symbol, Proc, #call] :unless gate `(task, error, attempt)` for retries
|
|
31
|
+
# @yield [attempt, delay] optional custom jitter block
|
|
32
|
+
# @return [Retry]
|
|
33
|
+
def retry_on(*exceptions, **options, &)
|
|
34
|
+
@retry_on ||=
|
|
35
|
+
if superclass.respond_to?(:retry_on)
|
|
36
|
+
superclass.retry_on.build(exceptions, options, &)
|
|
37
|
+
else
|
|
38
|
+
Retry.new(exceptions, options, &)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
return @retry_on if exceptions.empty?
|
|
42
|
+
|
|
43
|
+
@retry_on = @retry_on.build(exceptions, options, &)
|
|
44
|
+
end
|
|
20
45
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
46
|
+
# Reads or extends this class's {Settings}. Inherits from the superclass.
|
|
47
|
+
#
|
|
48
|
+
# @param options [Hash{Symbol => Object}] merged onto the current settings
|
|
49
|
+
# @option options [Logger] :logger (see {Settings#initialize})
|
|
50
|
+
# @option options [#call] :log_formatter (see {Settings#initialize})
|
|
51
|
+
# @option options [Integer] :log_level (see {Settings#initialize})
|
|
52
|
+
# @option options [#call] :backtrace_cleaner (see {Settings#initialize})
|
|
53
|
+
# @option options [Array<Symbol>] :log_exclusions (see {Settings#initialize})
|
|
54
|
+
# @option options [Array<Symbol, String>] :tags (see {Settings#initialize})
|
|
55
|
+
# @option options [Boolean] :strict_context (see {Settings#initialize})
|
|
56
|
+
# @return [Settings]
|
|
57
|
+
def settings(options = EMPTY_HASH)
|
|
58
|
+
@settings ||=
|
|
59
|
+
if superclass.respond_to?(:settings)
|
|
60
|
+
superclass.settings.build(options)
|
|
61
|
+
else
|
|
62
|
+
Settings.new(options)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
return @settings if options.empty?
|
|
66
|
+
|
|
67
|
+
@settings = @settings.build(options)
|
|
68
|
+
end
|
|
30
69
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
70
|
+
# @return [Middlewares] cloned from superclass/configuration on first call
|
|
71
|
+
def middlewares
|
|
72
|
+
@middlewares ||=
|
|
73
|
+
if superclass.respond_to?(:middlewares)
|
|
74
|
+
superclass.middlewares.dup
|
|
75
|
+
else
|
|
76
|
+
CMDx.configuration.middlewares.dup
|
|
77
|
+
end
|
|
78
|
+
end
|
|
40
79
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
alias ctx context
|
|
80
|
+
# @return [Callbacks] cloned from superclass/configuration on first call
|
|
81
|
+
def callbacks
|
|
82
|
+
@callbacks ||=
|
|
83
|
+
if superclass.respond_to?(:callbacks)
|
|
84
|
+
superclass.callbacks.dup
|
|
85
|
+
else
|
|
86
|
+
CMDx.configuration.callbacks.dup
|
|
87
|
+
end
|
|
88
|
+
end
|
|
51
89
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
# task.result.status # => "success"
|
|
58
|
-
#
|
|
59
|
-
# @rbs @result: Result
|
|
60
|
-
attr_reader :result
|
|
61
|
-
alias res result
|
|
90
|
+
Callbacks::EVENTS.each do |event|
|
|
91
|
+
define_method(event) do |callable = nil, **options, &block|
|
|
92
|
+
register(:callback, event, callable, **options, &block)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
62
95
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
96
|
+
# @return [Telemetry] cloned from superclass/configuration on first call
|
|
97
|
+
def telemetry
|
|
98
|
+
@telemetry ||=
|
|
99
|
+
if superclass.respond_to?(:telemetry)
|
|
100
|
+
superclass.telemetry.dup
|
|
101
|
+
else
|
|
102
|
+
CMDx.configuration.telemetry.dup
|
|
103
|
+
end
|
|
104
|
+
end
|
|
72
105
|
|
|
73
|
-
|
|
74
|
-
|
|
106
|
+
# @return [Coercions] cloned from superclass/configuration on first call
|
|
107
|
+
def coercions
|
|
108
|
+
@coercions ||=
|
|
109
|
+
if superclass.respond_to?(:coercions)
|
|
110
|
+
superclass.coercions.dup
|
|
111
|
+
else
|
|
112
|
+
CMDx.configuration.coercions.dup
|
|
113
|
+
end
|
|
114
|
+
end
|
|
75
115
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
# task = MyTask.new(Context.build(name: "example"))
|
|
86
|
-
#
|
|
87
|
-
# @rbs (untyped context) -> void
|
|
88
|
-
def initialize(context = nil)
|
|
89
|
-
Deprecator.restrict(self)
|
|
116
|
+
# @return [Validators] cloned from superclass/configuration on first call
|
|
117
|
+
def validators
|
|
118
|
+
@validators ||=
|
|
119
|
+
if superclass.respond_to?(:validators)
|
|
120
|
+
superclass.validators.dup
|
|
121
|
+
else
|
|
122
|
+
CMDx.configuration.validators.dup
|
|
123
|
+
end
|
|
124
|
+
end
|
|
90
125
|
|
|
91
|
-
@
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
126
|
+
# @return [Executors] cloned from superclass/configuration on first call
|
|
127
|
+
def executors
|
|
128
|
+
@executors ||=
|
|
129
|
+
if superclass.respond_to?(:executors)
|
|
130
|
+
superclass.executors.dup
|
|
131
|
+
else
|
|
132
|
+
CMDx.configuration.executors.dup
|
|
133
|
+
end
|
|
134
|
+
end
|
|
96
135
|
|
|
97
|
-
@
|
|
98
|
-
|
|
136
|
+
# @return [Mergers] cloned from superclass/configuration on first call
|
|
137
|
+
def mergers
|
|
138
|
+
@mergers ||=
|
|
139
|
+
if superclass.respond_to?(:mergers)
|
|
140
|
+
superclass.mergers.dup
|
|
141
|
+
else
|
|
142
|
+
CMDx.configuration.mergers.dup
|
|
143
|
+
end
|
|
144
|
+
end
|
|
99
145
|
|
|
100
|
-
|
|
146
|
+
# @return [Retriers] cloned from superclass/configuration on first call
|
|
147
|
+
def retriers
|
|
148
|
+
@retriers ||=
|
|
149
|
+
if superclass.respond_to?(:retriers)
|
|
150
|
+
superclass.retriers.dup
|
|
151
|
+
else
|
|
152
|
+
CMDx.configuration.retriers.dup
|
|
153
|
+
end
|
|
154
|
+
end
|
|
101
155
|
|
|
102
|
-
#
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
156
|
+
# @return [Deprecators] cloned from superclass/configuration on first call
|
|
157
|
+
def deprecators
|
|
158
|
+
@deprecators ||=
|
|
159
|
+
if superclass.respond_to?(:deprecators)
|
|
160
|
+
superclass.deprecators.dup
|
|
161
|
+
else
|
|
162
|
+
CMDx.configuration.deprecators.dup
|
|
163
|
+
end
|
|
109
164
|
end
|
|
110
165
|
|
|
111
|
-
#
|
|
112
|
-
# On first access, inherits from the superclass settings or
|
|
113
|
-
# the global Configuration. Optional overrides are applied once.
|
|
114
|
-
#
|
|
115
|
-
# @param overrides [Hash] Configuration overrides applied on first access
|
|
116
|
-
# @option overrides [Object] :* Any configuration override key-value pairs
|
|
117
|
-
#
|
|
118
|
-
# @return [Settings] The settings instance for this task class
|
|
166
|
+
# Dispatches to the appropriate registry's `register` method.
|
|
119
167
|
#
|
|
120
|
-
# @
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
168
|
+
# @param type [:middleware, :callback, :coercion, :validator, :executor, :merger, :retrier, :deprecator, :input, :output]
|
|
169
|
+
# @return [Object] the registry's self
|
|
170
|
+
# @raise [ArgumentError] when `type` is unknown
|
|
171
|
+
def register(type, ...)
|
|
172
|
+
case type
|
|
173
|
+
when :middleware
|
|
174
|
+
middlewares.register(...)
|
|
175
|
+
when :callback
|
|
176
|
+
callbacks.register(...)
|
|
177
|
+
when :coercion
|
|
178
|
+
coercions.register(...)
|
|
179
|
+
when :validator
|
|
180
|
+
validators.register(...)
|
|
181
|
+
when :executor
|
|
182
|
+
executors.register(...)
|
|
183
|
+
when :merger
|
|
184
|
+
mergers.register(...)
|
|
185
|
+
when :retrier
|
|
186
|
+
retriers.register(...)
|
|
187
|
+
when :deprecator
|
|
188
|
+
deprecators.register(...)
|
|
189
|
+
when :input
|
|
190
|
+
inputs.register(self, ...)
|
|
191
|
+
when :output
|
|
192
|
+
outputs.register(...)
|
|
193
|
+
else raise ArgumentError, "unknown registry type: #{type.inspect}"
|
|
130
194
|
end
|
|
131
195
|
end
|
|
132
196
|
|
|
133
|
-
#
|
|
134
|
-
# @param object [Object] The object to register
|
|
135
|
-
#
|
|
136
|
-
# @raise [RuntimeError] If the registry type is unknown
|
|
197
|
+
# Dispatches to the appropriate registry's `deregister` method.
|
|
137
198
|
#
|
|
138
|
-
# @
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
|
|
142
|
-
# @rbs (Symbol type, untyped object, *untyped) -> void
|
|
143
|
-
def register(type, object, ...)
|
|
199
|
+
# @param type [:middleware, :callback, :coercion, :validator, :executor, :merger, :retrier, :deprecator, :input, :output]
|
|
200
|
+
# @return [Object] the registry's self
|
|
201
|
+
# @raise [ArgumentError] when `type` is unknown
|
|
202
|
+
def deregister(type, ...)
|
|
144
203
|
case type
|
|
145
|
-
when :
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
when :
|
|
150
|
-
|
|
151
|
-
when :
|
|
152
|
-
|
|
204
|
+
when :middleware
|
|
205
|
+
middlewares.deregister(...)
|
|
206
|
+
when :callback
|
|
207
|
+
callbacks.deregister(...)
|
|
208
|
+
when :coercion
|
|
209
|
+
coercions.deregister(...)
|
|
210
|
+
when :validator
|
|
211
|
+
validators.deregister(...)
|
|
212
|
+
when :executor
|
|
213
|
+
executors.deregister(...)
|
|
214
|
+
when :merger
|
|
215
|
+
mergers.deregister(...)
|
|
216
|
+
when :retrier
|
|
217
|
+
retriers.deregister(...)
|
|
218
|
+
when :deprecator
|
|
219
|
+
deprecators.deregister(...)
|
|
220
|
+
when :input
|
|
221
|
+
inputs.deregister(self, ...)
|
|
222
|
+
when :output
|
|
223
|
+
outputs.deregister(...)
|
|
224
|
+
else raise ArgumentError, "unknown registry type: #{type.inspect}"
|
|
153
225
|
end
|
|
154
226
|
end
|
|
155
227
|
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
# @
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
# @
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
when :coercion then settings.coercions.deregister(object, ...)
|
|
175
|
-
else raise "unknown registry type #{type.inspect}"
|
|
228
|
+
# Reads, sets, or inherits the task class's {Deprecation}. With a
|
|
229
|
+
# `value` or block, replaces any current deprecation. Otherwise returns
|
|
230
|
+
# the locally defined one, or the superclass's.
|
|
231
|
+
#
|
|
232
|
+
# @param value [:log, :warn, :error, Symbol, Proc, #call, nil]
|
|
233
|
+
# @param block [#call, nil] optional block used as the deprecation callable
|
|
234
|
+
# @param options [Hash{Symbol => Object}] `:if`/`:unless` conditions (see {Deprecation#initialize})
|
|
235
|
+
# @option options [Symbol, Proc, #call] :if (see {Deprecation#initialize})
|
|
236
|
+
# @option options [Symbol, Proc, #call] :unless (see {Deprecation#initialize})
|
|
237
|
+
# @return [Deprecation, nil]
|
|
238
|
+
# @yield optional block used as the deprecation callable
|
|
239
|
+
def deprecation(value = nil, **options, &block)
|
|
240
|
+
if value || block
|
|
241
|
+
@deprecation = Deprecation.new(value || block, options)
|
|
242
|
+
elsif defined?(@deprecation)
|
|
243
|
+
@deprecation
|
|
244
|
+
elsif superclass.respond_to?(:deprecation)
|
|
245
|
+
superclass.deprecation
|
|
176
246
|
end
|
|
177
247
|
end
|
|
178
248
|
|
|
179
|
-
#
|
|
180
|
-
#
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
# @
|
|
184
|
-
|
|
185
|
-
|
|
249
|
+
# Reads, or declares more, inputs. With no names, returns the registry;
|
|
250
|
+
# with names, registers them and defines accessors.
|
|
251
|
+
#
|
|
252
|
+
# @param names [Array<Symbol>]
|
|
253
|
+
# @param options [Hash{Symbol => Object}] see {Input#initialize}
|
|
254
|
+
# @option options [String] :description (also accepts `:desc`)
|
|
255
|
+
# @option options [Symbol] :as overrides the accessor name
|
|
256
|
+
# @option options [Boolean, String] :prefix prefix for the accessor name
|
|
257
|
+
# @option options [Boolean, String] :suffix suffix for the accessor name
|
|
258
|
+
# @option options [Symbol, Proc, #call] :source (`:context`) where to fetch from
|
|
259
|
+
# @option options [Object, Symbol, Proc, #call] :default
|
|
260
|
+
# @option options [Symbol, Proc, #call] :transform mutator applied after coercion
|
|
261
|
+
# @option options [Symbol, Proc, #call] :if
|
|
262
|
+
# @option options [Symbol, Proc, #call] :unless
|
|
263
|
+
# @option options [Boolean] :required
|
|
264
|
+
# @option options [Object] :coerce (see {Coercions#extract})
|
|
265
|
+
# @option options [Object] :validate (see {Validators#extract})
|
|
266
|
+
# @yield nested-input DSL block (see {Inputs::ChildBuilder})
|
|
267
|
+
# @return [Inputs]
|
|
268
|
+
def inputs(*names, **options, &)
|
|
269
|
+
@inputs ||=
|
|
270
|
+
if superclass.respond_to?(:inputs)
|
|
271
|
+
superclass.inputs.dup
|
|
272
|
+
else
|
|
273
|
+
Inputs.new
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
return @inputs if names.empty?
|
|
277
|
+
|
|
278
|
+
@inputs.register(self, *names, **options, &)
|
|
279
|
+
end
|
|
280
|
+
alias input inputs
|
|
281
|
+
|
|
282
|
+
# Declares optional inputs (shorthand for `inputs ..., required: false`).
|
|
283
|
+
#
|
|
284
|
+
# @param names [Array<Symbol>]
|
|
285
|
+
# @param options [Hash{Symbol => Object}] see {Input#initialize}
|
|
286
|
+
# @option options [String] :description (also accepts `:desc`)
|
|
287
|
+
# @option options [Symbol] :as overrides the accessor name
|
|
288
|
+
# @option options [Boolean, String] :prefix prefix for the accessor name
|
|
289
|
+
# @option options [Boolean, String] :suffix suffix for the accessor name
|
|
290
|
+
# @option options [Symbol, Proc, #call] :source (`:context`) where to fetch from
|
|
291
|
+
# @option options [Object, Symbol, Proc, #call] :default
|
|
292
|
+
# @option options [Symbol, Proc, #call] :transform mutator applied after coercion
|
|
293
|
+
# @option options [Symbol, Proc, #call] :if
|
|
294
|
+
# @option options [Symbol, Proc, #call] :unless
|
|
295
|
+
# @option options [Object] :coerce (see {Coercions#extract})
|
|
296
|
+
# @option options [Object] :validate (see {Validators#extract})
|
|
297
|
+
# @yield nested-input DSL block (see {Inputs::ChildBuilder})
|
|
298
|
+
def optional(*names, **options, &)
|
|
299
|
+
register(:input, *names, required: false, **options, &)
|
|
186
300
|
end
|
|
187
|
-
alias attribute attributes
|
|
188
301
|
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
#
|
|
192
|
-
#
|
|
193
|
-
# @
|
|
194
|
-
|
|
195
|
-
|
|
302
|
+
# Declares required inputs (shorthand for `inputs ..., required: true`).
|
|
303
|
+
#
|
|
304
|
+
# @param names [Array<Symbol>]
|
|
305
|
+
# @param options [Hash{Symbol => Object}] see {Input#initialize}
|
|
306
|
+
# @option options [String] :description (also accepts `:desc`)
|
|
307
|
+
# @option options [Symbol] :as overrides the accessor name
|
|
308
|
+
# @option options [Boolean, String] :prefix prefix for the accessor name
|
|
309
|
+
# @option options [Boolean, String] :suffix suffix for the accessor name
|
|
310
|
+
# @option options [Symbol, Proc, #call] :source (`:context`) where to fetch from
|
|
311
|
+
# @option options [Object, Symbol, Proc, #call] :default
|
|
312
|
+
# @option options [Symbol, Proc, #call] :transform mutator applied after coercion
|
|
313
|
+
# @option options [Symbol, Proc, #call] :if
|
|
314
|
+
# @option options [Symbol, Proc, #call] :unless
|
|
315
|
+
# @option options [Object] :coerce (see {Coercions#extract})
|
|
316
|
+
# @option options [Object] :validate (see {Validators#extract})
|
|
317
|
+
# @yield nested-input DSL block (see {Inputs::ChildBuilder})
|
|
318
|
+
def required(*names, **options, &)
|
|
319
|
+
register(:input, *names, required: true, **options, &)
|
|
196
320
|
end
|
|
197
321
|
|
|
198
|
-
# @
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
#
|
|
202
|
-
# @rbs (*untyped) -> void
|
|
203
|
-
def required(...)
|
|
204
|
-
register(:attribute, Attribute.required(...))
|
|
322
|
+
# @return [Hash{Symbol => Hash}] serialized input definitions
|
|
323
|
+
def inputs_schema
|
|
324
|
+
inputs.registry.transform_values(&:to_h)
|
|
205
325
|
end
|
|
206
326
|
|
|
207
|
-
#
|
|
208
|
-
#
|
|
209
|
-
# @
|
|
210
|
-
#
|
|
211
|
-
#
|
|
212
|
-
# @
|
|
213
|
-
|
|
214
|
-
|
|
327
|
+
# Reads, or declares more, outputs. With no keys, returns the registry.
|
|
328
|
+
#
|
|
329
|
+
# @param keys [Array<Symbol>]
|
|
330
|
+
# @param options [Hash{Symbol => Object}] see {Output#initialize}
|
|
331
|
+
# @option options [String] :description (also accepts `:desc`)
|
|
332
|
+
# @option options [Symbol, Proc, #call] :if
|
|
333
|
+
# @option options [Symbol, Proc, #call] :unless
|
|
334
|
+
# @option options [Object, Symbol, Proc, #call] :default
|
|
335
|
+
# @return [Outputs]
|
|
336
|
+
def outputs(*keys, **options)
|
|
337
|
+
@outputs ||=
|
|
338
|
+
if superclass.respond_to?(:outputs)
|
|
339
|
+
superclass.outputs.dup
|
|
340
|
+
else
|
|
341
|
+
Outputs.new
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
return @outputs if keys.empty?
|
|
345
|
+
|
|
346
|
+
@outputs.register(*keys, **options)
|
|
215
347
|
end
|
|
216
|
-
alias
|
|
348
|
+
alias output outputs
|
|
217
349
|
|
|
218
|
-
#
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
#
|
|
222
|
-
# @param names [Array<Symbol, String>] Names of expected return keys in the context
|
|
223
|
-
#
|
|
224
|
-
# @example
|
|
225
|
-
# returns :user, :token
|
|
226
|
-
#
|
|
227
|
-
# @rbs (*untyped names) -> void
|
|
228
|
-
def returns(*names)
|
|
229
|
-
settings.returns |= names.map(&:to_sym)
|
|
350
|
+
# @return [Hash{Symbol => Hash}] serialized output definitions
|
|
351
|
+
def outputs_schema
|
|
352
|
+
outputs.registry.transform_values(&:to_h)
|
|
230
353
|
end
|
|
231
354
|
|
|
232
|
-
#
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
#
|
|
236
|
-
# @example
|
|
237
|
-
# remove_returns :old_return
|
|
238
|
-
#
|
|
239
|
-
# @rbs (*Symbol names) -> void
|
|
240
|
-
def remove_returns(*names)
|
|
241
|
-
settings.returns -= names.map(&:to_sym)
|
|
355
|
+
# @return [String] `"Workflow"` when the class includes {Workflow}, else `"Task"`
|
|
356
|
+
def type
|
|
357
|
+
@type ||= include?(Workflow) ? "Workflow" : "Task"
|
|
242
358
|
end
|
|
243
|
-
alias remove_return remove_returns
|
|
244
359
|
|
|
245
|
-
#
|
|
360
|
+
# Executes the task. Never raises on failure; inspect the returned
|
|
361
|
+
# {Result} instead.
|
|
246
362
|
#
|
|
247
|
-
# @
|
|
248
|
-
#
|
|
249
|
-
#
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
#
|
|
363
|
+
# @param context [Hash, Context, #context, #to_h]
|
|
364
|
+
# @yieldparam result [Result]
|
|
365
|
+
# @return [Result, Object] the yielded block's value when a block is given
|
|
366
|
+
def execute(context = EMPTY_HASH, &)
|
|
367
|
+
new(context).execute(strict: false, &)
|
|
368
|
+
end
|
|
369
|
+
alias call execute
|
|
370
|
+
|
|
371
|
+
# Strict execution. Raises {Fault} (or the underlying exception) on
|
|
372
|
+
# failure; otherwise identical to {.execute}.
|
|
256
373
|
#
|
|
257
|
-
# @
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
374
|
+
# @param context [Hash, Context, #context, #to_h]
|
|
375
|
+
# @yieldparam result [Result]
|
|
376
|
+
# @return [Result, Object]
|
|
377
|
+
# @raise [Fault, StandardError] on task failure
|
|
378
|
+
def execute!(context = EMPTY_HASH, &)
|
|
379
|
+
new(context).execute(strict: true, &)
|
|
262
380
|
end
|
|
381
|
+
alias call! execute!
|
|
382
|
+
|
|
383
|
+
private
|
|
384
|
+
|
|
385
|
+
# @param input [Input] defines `##{input.accessor_name}` when not already taken
|
|
386
|
+
# @return [void]
|
|
387
|
+
# @raise [DefinitionError] when the accessor name collides
|
|
388
|
+
def define_input_reader(input)
|
|
389
|
+
accessor = input.accessor_name
|
|
263
390
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
# @option options [Symbol] :priority Priority of the callback
|
|
268
|
-
# @option options [Boolean] :async Whether the callback should run asynchronously
|
|
269
|
-
# @param block [Proc] Block to register as a callback
|
|
270
|
-
#
|
|
271
|
-
# @example
|
|
272
|
-
# before { puts "before execution" }
|
|
273
|
-
# after :cleanup, priority: :high
|
|
274
|
-
# around ->(task) { task.logger.info("starting") }
|
|
275
|
-
#
|
|
276
|
-
# @rbs (*untyped callables, **untyped options) ?{ () -> void } -> void
|
|
277
|
-
define_method(callback) do |*callables, **options, &block|
|
|
278
|
-
register(:callback, callback, *callables, **options, &block)
|
|
391
|
+
if method_defined?(accessor) || private_method_defined?(accessor)
|
|
392
|
+
raise DefinitionError,
|
|
393
|
+
"cannot define input #{accessor.inspect}: ##{accessor} is already defined on #{self}"
|
|
279
394
|
end
|
|
280
|
-
end
|
|
281
395
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
# @option kwargs [Object] :* Any key-value pairs to pass to the task constructor
|
|
285
|
-
#
|
|
286
|
-
# @return [Result] The execution result
|
|
287
|
-
#
|
|
288
|
-
# @example
|
|
289
|
-
# result = MyTask.execute(name: "example")
|
|
290
|
-
#
|
|
291
|
-
# @rbs (*untyped args, dry_run: bool, **untyped kwargs) ?{ (Result) -> void } -> Result
|
|
292
|
-
def execute(*args, **kwargs)
|
|
293
|
-
task = new(*args, **kwargs)
|
|
294
|
-
task.execute(raise: false)
|
|
295
|
-
block_given? ? yield(task.result) : task.result
|
|
396
|
+
define_method(accessor) { instance_variable_get(input.ivar_name) }
|
|
397
|
+
input.children.each { |child| define_input_reader(child) }
|
|
296
398
|
end
|
|
297
399
|
|
|
298
|
-
# @param
|
|
299
|
-
# @
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
# @raise [ExecutionError] If the task execution fails
|
|
305
|
-
#
|
|
306
|
-
# @example
|
|
307
|
-
# result = MyTask.execute!(name: "example")
|
|
308
|
-
#
|
|
309
|
-
# @rbs (*untyped args, dry_run: bool, **untyped kwargs) ?{ (Result) -> void } -> Result
|
|
310
|
-
def execute!(*args, **kwargs)
|
|
311
|
-
task = new(*args, **kwargs)
|
|
312
|
-
task.execute(raise: true)
|
|
313
|
-
block_given? ? yield(task.result) : task.result
|
|
400
|
+
# @param input [Input] removes `##{input.accessor_name}` if defined on this class
|
|
401
|
+
# @return [void]
|
|
402
|
+
def undefine_input_reader(input)
|
|
403
|
+
accessor = input.accessor_name
|
|
404
|
+
undef_method(accessor) if method_defined?(accessor)
|
|
405
|
+
input.children.each { |child| undefine_input_reader(child) }
|
|
314
406
|
end
|
|
315
407
|
|
|
316
408
|
end
|
|
317
409
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
#
|
|
322
|
-
# @
|
|
323
|
-
#
|
|
324
|
-
#
|
|
410
|
+
attr_reader :tid, :context, :errors, :metadata
|
|
411
|
+
alias ctx context
|
|
412
|
+
|
|
413
|
+
# @param context [Hash, Context, #context, #to_h]
|
|
414
|
+
# @note The built {Context} inherits `strict` mode from
|
|
415
|
+
# {Settings#strict_context} (falling back to
|
|
416
|
+
# {Configuration#strict_context}), so dynamic reads for unknown keys
|
|
417
|
+
# raise `NoMethodError` instead of returning `nil`.
|
|
418
|
+
def initialize(context = EMPTY_HASH)
|
|
419
|
+
@metadata = {}
|
|
420
|
+
@tid = SecureRandom.uuid_v7
|
|
421
|
+
@errors = Errors.new
|
|
422
|
+
@context = Context.build(context).tap do |c|
|
|
423
|
+
c.strict = self.class.settings.strict_context
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# Executes this task instance through {Runtime}.
|
|
325
428
|
#
|
|
326
|
-
# @
|
|
327
|
-
|
|
328
|
-
|
|
429
|
+
# @param strict [Boolean] when `true`, re-raises {Fault}/exceptions on failure;
|
|
430
|
+
# when `false`, swallows them and returns the {Result}
|
|
431
|
+
# @yieldparam result [Result]
|
|
432
|
+
# @return [Result, Object] the yielded block's value when a block is given,
|
|
433
|
+
# otherwise the {Result}
|
|
434
|
+
# @raise [Fault, StandardError] only when `strict: true` and the task fails
|
|
435
|
+
def execute(strict: false)
|
|
436
|
+
result = Runtime.execute(self, strict:)
|
|
329
437
|
block_given? ? yield(result) : result
|
|
330
438
|
end
|
|
439
|
+
alias call execute
|
|
331
440
|
|
|
332
|
-
# @
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
#
|
|
338
|
-
# puts "Performing work..."
|
|
339
|
-
# end
|
|
340
|
-
# end
|
|
441
|
+
# @return [Logger] a logger tailored to this task's settings
|
|
442
|
+
def logger
|
|
443
|
+
@logger ||= LoggerProxy.logger(self)
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
# The task's core logic. Subclasses must override.
|
|
341
447
|
#
|
|
342
|
-
# @
|
|
448
|
+
# @abstract
|
|
449
|
+
# @return [void]
|
|
450
|
+
# @raise [ImplementationError] when the subclass doesn't override
|
|
343
451
|
def work
|
|
344
|
-
raise
|
|
452
|
+
raise ImplementationError, "undefined method #{self.class}#work"
|
|
345
453
|
end
|
|
346
454
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
#
|
|
350
|
-
#
|
|
351
|
-
# @return [Logger] The logger instance for this task
|
|
352
|
-
#
|
|
353
|
-
# @example
|
|
354
|
-
# logger.info "Starting task execution"
|
|
355
|
-
# logger.error "Task failed", error: exception
|
|
455
|
+
private
|
|
456
|
+
|
|
457
|
+
# Signals a successful halt.
|
|
356
458
|
#
|
|
357
|
-
# @
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
log_instance.level = settings.log_level if settings.log_level
|
|
366
|
-
log_instance.formatter = settings.log_formatter if settings.log_formatter
|
|
367
|
-
end
|
|
459
|
+
# @param reason [String, nil]
|
|
460
|
+
# @param sigdata [Hash{Symbol => Object}] arbitrary metadata merged into {#metadata} before throwing
|
|
461
|
+
# @option sigdata [Object] arbitrary entries merged via `metadata.merge!`
|
|
462
|
+
# @return [void] throws `Signal::TAG`; never returns
|
|
463
|
+
# @raise [FrozenError] when the task has already been frozen (post-execution)
|
|
464
|
+
# @note Must be called from inside `work` (inside Runtime's `catch(:cmdx_signal)`).
|
|
465
|
+
def success!(reason = nil, **sigdata)
|
|
466
|
+
raise FrozenError, "cannot throw signals" if frozen?
|
|
368
467
|
|
|
369
|
-
|
|
370
|
-
|
|
468
|
+
metadata.merge!(sigdata) unless sigdata.empty?
|
|
469
|
+
throw(Signal::TAG, Signal.success(reason, metadata:))
|
|
371
470
|
end
|
|
372
471
|
|
|
373
|
-
#
|
|
374
|
-
# @option return [String] :chain_id The chain identifier
|
|
375
|
-
# @option return [String] :type The task type ("Task" or "Workflow")
|
|
376
|
-
# @option return [Array<Symbol>] :tags The task tags
|
|
377
|
-
# @option return [String] :class The task class name
|
|
378
|
-
# @option return [String] :id The task identifier
|
|
379
|
-
# @option return [Hash] :context The task context (when dump_context is true)
|
|
380
|
-
#
|
|
381
|
-
# @return [Hash] A hash representation of the task
|
|
472
|
+
# Signals a skip (interrupted + skipped).
|
|
382
473
|
#
|
|
383
|
-
# @
|
|
384
|
-
#
|
|
385
|
-
#
|
|
386
|
-
#
|
|
387
|
-
#
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
type: self.class.type,
|
|
394
|
-
class: self.class.name,
|
|
395
|
-
id:,
|
|
396
|
-
dry_run: dry_run?,
|
|
397
|
-
tags: self.class.settings.tags
|
|
398
|
-
}.tap do |hash|
|
|
399
|
-
if self.class.settings.dump_context
|
|
400
|
-
# Large context can make dumps and logs very noisy,
|
|
401
|
-
# so only include it if explicitly enabled
|
|
402
|
-
hash[:context] = context.to_h
|
|
403
|
-
end
|
|
404
|
-
end
|
|
474
|
+
# @param reason [String, nil]
|
|
475
|
+
# @param sigdata [Hash{Symbol => Object}] arbitrary metadata merged into {#metadata} before throwing
|
|
476
|
+
# @option sigdata [Object] arbitrary entries merged via `metadata.merge!`
|
|
477
|
+
# @return [void] throws `Signal::TAG`; never returns
|
|
478
|
+
# @raise [FrozenError]
|
|
479
|
+
def skip!(reason = nil, **sigdata)
|
|
480
|
+
raise FrozenError, "cannot throw signals" if frozen?
|
|
481
|
+
|
|
482
|
+
metadata.merge!(sigdata) unless sigdata.empty?
|
|
483
|
+
throw(Signal::TAG, Signal.skipped(reason, metadata:))
|
|
405
484
|
end
|
|
406
485
|
|
|
407
|
-
#
|
|
486
|
+
# Signals a failure. Captures current call frames as the signal
|
|
487
|
+
# backtrace for Fault propagation.
|
|
408
488
|
#
|
|
409
|
-
# @
|
|
410
|
-
#
|
|
411
|
-
#
|
|
489
|
+
# @param reason [String, nil]
|
|
490
|
+
# @param sigdata [Hash{Symbol => Object}] arbitrary metadata merged into {#metadata} before throwing
|
|
491
|
+
# @option sigdata [Object] arbitrary entries merged via `metadata.merge!`
|
|
492
|
+
# @return [void] throws `Signal::TAG`; never returns
|
|
493
|
+
# @raise [FrozenError]
|
|
494
|
+
def fail!(reason = nil, **sigdata)
|
|
495
|
+
raise FrozenError, "cannot throw signals" if frozen?
|
|
496
|
+
|
|
497
|
+
metadata.merge!(sigdata) unless sigdata.empty?
|
|
498
|
+
throw(Signal::TAG, Signal.failed(reason, metadata:, backtrace: caller_locations(1)))
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Re-throws a failed peer Result's signal through this task. No-op when
|
|
502
|
+
# `other` didn't fail.
|
|
412
503
|
#
|
|
413
|
-
# @
|
|
414
|
-
|
|
415
|
-
|
|
504
|
+
# @param other [Result]
|
|
505
|
+
# @param sigdata [Hash{Symbol => Object}] arbitrary metadata merged into {#metadata} before echoing
|
|
506
|
+
# @option sigdata [Object] arbitrary entries merged via `metadata.merge!`
|
|
507
|
+
# @return [void]
|
|
508
|
+
# @raise [FrozenError]
|
|
509
|
+
def throw!(other, **sigdata)
|
|
510
|
+
raise FrozenError, "cannot throw signals" if frozen?
|
|
511
|
+
|
|
512
|
+
return unless other.failed?
|
|
513
|
+
|
|
514
|
+
metadata.merge!(sigdata) unless sigdata.empty?
|
|
515
|
+
throw(Signal::TAG, Signal.echoed(other, metadata:, backtrace: caller_locations(1)))
|
|
416
516
|
end
|
|
417
517
|
|
|
418
518
|
end
|