Class: CMDx::Task

Inherits:
Object
  • Object
show all
Defined in:
lib/cmdx/task.rb

Overview

Base class for all units of work. Subclasses override ‘#work` and declare their contract via `required`, `optional`, `output`, `callbacks`, `retry_on`, `deprecation`, and `settings`. Invoked via Task.execute (safe) or Task.execute! (strict, raises on failure).

Inheritance: every registry accessor (middlewares, callbacks, coercions, validators, executors, mergers, telemetry, inputs, outputs) lazily clones from the superclass’s registry (or the global configuration at the top of the hierarchy), so subclasses extend rather than replace.

See Also:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context = EMPTY_HASH) ⇒ Task

Note:

The built Context inherits ‘strict` mode from Settings#strict_context (falling back to Configuration#strict_context), so dynamic reads for unknown keys raise `NoMethodError` instead of returning `nil`.

Returns a new instance of Task.

Parameters:



418
419
420
421
422
423
424
425
# File 'lib/cmdx/task.rb', line 418

def initialize(context = EMPTY_HASH)
  @metadata = {}
  @tid      = SecureRandom.uuid_v7
  @errors   = Errors.new
  @context  = Context.build(context).tap do |c|
    c.strict = self.class.settings.strict_context
  end
end

Instance Attribute Details

#contextObject (readonly) Also known as: ctx

Returns the value of attribute context.



410
411
412
# File 'lib/cmdx/task.rb', line 410

def context
  @context
end

#errorsObject (readonly)

Returns the value of attribute errors.



410
411
412
# File 'lib/cmdx/task.rb', line 410

def errors
  @errors
end

#metadataObject (readonly)

Returns the value of attribute metadata.



410
411
412
# File 'lib/cmdx/task.rb', line 410

def 
  @metadata
end

#tidObject (readonly)

Returns the value of attribute tid.



410
411
412
# File 'lib/cmdx/task.rb', line 410

def tid
  @tid
end

Class Method Details

.call {|result| ... } ⇒ Result, Object

Executes the task. Never raises on failure; inspect the returned Result instead.

Parameters:

Yield Parameters:

Returns:

  • (Result, Object)

    the yielded block’s value when a block is given



369
370
371
# File 'lib/cmdx/task.rb', line 369

def execute(context = EMPTY_HASH, &)
  new(context).execute(strict: false, &)
end

.callbacksCallbacks

Returns cloned from superclass/configuration on first call.

Returns:

  • (Callbacks)

    cloned from superclass/configuration on first call



81
82
83
84
85
86
87
88
# File 'lib/cmdx/task.rb', line 81

def callbacks
  @callbacks ||=
    if superclass.respond_to?(:callbacks)
      superclass.callbacks.dup
    else
      CMDx.configuration.callbacks.dup
    end
end

.coercionsCoercions

Returns cloned from superclass/configuration on first call.

Returns:

  • (Coercions)

    cloned from superclass/configuration on first call



107
108
109
110
111
112
113
114
# File 'lib/cmdx/task.rb', line 107

def coercions
  @coercions ||=
    if superclass.respond_to?(:coercions)
      superclass.coercions.dup
    else
      CMDx.configuration.coercions.dup
    end
end

.deprecation(value = nil, **options, &block) { ... } ⇒ Deprecation?

Reads, sets, or inherits the task class’s Deprecation. With a ‘value` or block, replaces any current deprecation. Otherwise returns the locally defined one, or the superclass’s.

Parameters:

  • value (:log, :warn, :error, Symbol, Proc, #call, nil) (defaults to: nil)
  • block (#call, nil)

    optional block used as the deprecation callable

  • options (Hash{Symbol => Object})

    ‘:if`/`:unless` conditions (see Deprecation#initialize)

Options Hash (**options):

  • :if (Symbol, Proc, #call) — default: see {Deprecation#initialize}
  • :unless (Symbol, Proc, #call) — default: see {Deprecation#initialize}

Yields:

  • optional block used as the deprecation callable

Returns:



239
240
241
242
243
244
245
246
247
# File 'lib/cmdx/task.rb', line 239

def deprecation(value = nil, **options, &block)
  if value || block
    @deprecation = Deprecation.new(value || block, options)
  elsif defined?(@deprecation)
    @deprecation
  elsif superclass.respond_to?(:deprecation)
    superclass.deprecation
  end
end

.deprecatorsDeprecators

Returns cloned from superclass/configuration on first call.

Returns:

  • (Deprecators)

    cloned from superclass/configuration on first call



157
158
159
160
161
162
163
164
# File 'lib/cmdx/task.rb', line 157

def deprecators
  @deprecators ||=
    if superclass.respond_to?(:deprecators)
      superclass.deprecators.dup
    else
      CMDx.configuration.deprecators.dup
    end
end

.deregister(type) ⇒ Object

Dispatches to the appropriate registry’s ‘deregister` method.

Parameters:

  • type (:middleware, :callback, :coercion, :validator, :executor, :merger, :retrier, :deprecator, :input, :output)

Returns:

  • (Object)

    the registry’s self

Raises:

  • (ArgumentError)

    when ‘type` is unknown



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/cmdx/task.rb', line 202

def deregister(type, ...)
  case type
  when :middleware
    middlewares.deregister(...)
  when :callback
    callbacks.deregister(...)
  when :coercion
    coercions.deregister(...)
  when :validator
    validators.deregister(...)
  when :executor
    executors.deregister(...)
  when :merger
    mergers.deregister(...)
  when :retrier
    retriers.deregister(...)
  when :deprecator
    deprecators.deregister(...)
  when :input
    inputs.deregister(self, ...)
  when :output
    outputs.deregister(...)
  else raise ArgumentError, "unknown registry type: #{type.inspect}"
  end
end

.execute(context = EMPTY_HASH) {|result| ... } ⇒ Result, Object

Executes the task. Never raises on failure; inspect the returned Result instead.

Parameters:

Yield Parameters:

Returns:

  • (Result, Object)

    the yielded block’s value when a block is given



366
367
368
# File 'lib/cmdx/task.rb', line 366

def execute(context = EMPTY_HASH, &)
  new(context).execute(strict: false, &)
end

.execute!(context = EMPTY_HASH) {|result| ... } ⇒ Result, Object Also known as: call!

Strict execution. Raises Fault (or the underlying exception) on failure; otherwise identical to execute.

Parameters:

Yield Parameters:

Returns:

Raises:

  • (Fault, StandardError)

    on task failure



378
379
380
# File 'lib/cmdx/task.rb', line 378

def execute!(context = EMPTY_HASH, &)
  new(context).execute(strict: true, &)
end

.executorsExecutors

Returns cloned from superclass/configuration on first call.

Returns:

  • (Executors)

    cloned from superclass/configuration on first call



127
128
129
130
131
132
133
134
# File 'lib/cmdx/task.rb', line 127

def executors
  @executors ||=
    if superclass.respond_to?(:executors)
      superclass.executors.dup
    else
      CMDx.configuration.executors.dup
    end
end

.inputs(*names, **options) { ... } ⇒ Inputs Also known as: input

Reads, or declares more, inputs. With no names, returns the registry; with names, registers them and defines accessors.

Parameters:

  • names (Array<Symbol>)
  • options (Hash{Symbol => Object})

Options Hash (**options):

  • :description (String) — default: also accepts `:desc`
  • :as (Symbol)

    overrides the accessor name

  • :prefix (Boolean, String)

    prefix for the accessor name

  • :suffix (Boolean, String)

    suffix for the accessor name

  • :source (Symbol, Proc, #call) — default: `:context`

    where to fetch from

  • :default (Object, Symbol, Proc, #call)
  • :transform (Symbol, Proc, #call)

    mutator applied after coercion

  • :if (Symbol, Proc, #call)
  • :unless (Symbol, Proc, #call)
  • :required (Boolean)
  • :coerce (Object) — default: see {Coercions#extract}
  • :validate (Object) — default: see {Validators#extract}

Yields:

Returns:



268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/cmdx/task.rb', line 268

def inputs(*names, **options, &)
  @inputs ||=
    if superclass.respond_to?(:inputs)
      superclass.inputs.dup
    else
      Inputs.new
    end

  return @inputs if names.empty?

  @inputs.register(self, *names, **options, &)
end

.inputs_schemaHash{Symbol => Hash}

Returns serialized input definitions.

Returns:

  • (Hash{Symbol => Hash})

    serialized input definitions



323
324
325
# File 'lib/cmdx/task.rb', line 323

def inputs_schema
  inputs.registry.transform_values(&:to_h)
end

.mergersMergers

Returns cloned from superclass/configuration on first call.

Returns:

  • (Mergers)

    cloned from superclass/configuration on first call



137
138
139
140
141
142
143
144
# File 'lib/cmdx/task.rb', line 137

def mergers
  @mergers ||=
    if superclass.respond_to?(:mergers)
      superclass.mergers.dup
    else
      CMDx.configuration.mergers.dup
    end
end

.middlewaresMiddlewares

Returns cloned from superclass/configuration on first call.

Returns:

  • (Middlewares)

    cloned from superclass/configuration on first call



71
72
73
74
75
76
77
78
# File 'lib/cmdx/task.rb', line 71

def middlewares
  @middlewares ||=
    if superclass.respond_to?(:middlewares)
      superclass.middlewares.dup
    else
      CMDx.configuration.middlewares.dup
    end
end

.optional(*names, **options) { ... } ⇒ Object

Declares optional inputs (shorthand for ‘inputs …, required: false`).

Parameters:

  • names (Array<Symbol>)
  • options (Hash{Symbol => Object})

Options Hash (**options):

  • :description (String) — default: also accepts `:desc`
  • :as (Symbol)

    overrides the accessor name

  • :prefix (Boolean, String)

    prefix for the accessor name

  • :suffix (Boolean, String)

    suffix for the accessor name

  • :source (Symbol, Proc, #call) — default: `:context`

    where to fetch from

  • :default (Object, Symbol, Proc, #call)
  • :transform (Symbol, Proc, #call)

    mutator applied after coercion

  • :if (Symbol, Proc, #call)
  • :unless (Symbol, Proc, #call)
  • :coerce (Object) — default: see {Coercions#extract}
  • :validate (Object) — default: see {Validators#extract}

Yields:



298
299
300
# File 'lib/cmdx/task.rb', line 298

def optional(*names, **options, &)
  register(:input, *names, required: false, **options, &)
end

.outputs(*keys, **options) ⇒ Outputs Also known as: output

Reads, or declares more, outputs. With no keys, returns the registry.

Parameters:

Options Hash (**options):

  • :description (String) — default: also accepts `:desc`
  • :if (Symbol, Proc, #call)
  • :unless (Symbol, Proc, #call)
  • :default (Object, Symbol, Proc, #call)

Returns:



336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/cmdx/task.rb', line 336

def outputs(*keys, **options)
  @outputs ||=
    if superclass.respond_to?(:outputs)
      superclass.outputs.dup
    else
      Outputs.new
    end

  return @outputs if keys.empty?

  @outputs.register(*keys, **options)
end

.outputs_schemaHash{Symbol => Hash}

Returns serialized output definitions.

Returns:

  • (Hash{Symbol => Hash})

    serialized output definitions



351
352
353
# File 'lib/cmdx/task.rb', line 351

def outputs_schema
  outputs.registry.transform_values(&:to_h)
end

.register(type) ⇒ Object

Dispatches to the appropriate registry’s ‘register` method.

Parameters:

  • type (:middleware, :callback, :coercion, :validator, :executor, :merger, :retrier, :deprecator, :input, :output)

Returns:

  • (Object)

    the registry’s self

Raises:

  • (ArgumentError)

    when ‘type` is unknown



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/cmdx/task.rb', line 171

def register(type, ...)
  case type
  when :middleware
    middlewares.register(...)
  when :callback
    callbacks.register(...)
  when :coercion
    coercions.register(...)
  when :validator
    validators.register(...)
  when :executor
    executors.register(...)
  when :merger
    mergers.register(...)
  when :retrier
    retriers.register(...)
  when :deprecator
    deprecators.register(...)
  when :input
    inputs.register(self, ...)
  when :output
    outputs.register(...)
  else raise ArgumentError, "unknown registry type: #{type.inspect}"
  end
end

.required(*names, **options) { ... } ⇒ Object

Declares required inputs (shorthand for ‘inputs …, required: true`).

Parameters:

  • names (Array<Symbol>)
  • options (Hash{Symbol => Object})

Options Hash (**options):

  • :description (String) — default: also accepts `:desc`
  • :as (Symbol)

    overrides the accessor name

  • :prefix (Boolean, String)

    prefix for the accessor name

  • :suffix (Boolean, String)

    suffix for the accessor name

  • :source (Symbol, Proc, #call) — default: `:context`

    where to fetch from

  • :default (Object, Symbol, Proc, #call)
  • :transform (Symbol, Proc, #call)

    mutator applied after coercion

  • :if (Symbol, Proc, #call)
  • :unless (Symbol, Proc, #call)
  • :coerce (Object) — default: see {Coercions#extract}
  • :validate (Object) — default: see {Validators#extract}

Yields:



318
319
320
# File 'lib/cmdx/task.rb', line 318

def required(*names, **options, &)
  register(:input, *names, required: true, **options, &)
end

.retriersRetriers

Returns cloned from superclass/configuration on first call.

Returns:

  • (Retriers)

    cloned from superclass/configuration on first call



147
148
149
150
151
152
153
154
# File 'lib/cmdx/task.rb', line 147

def retriers
  @retriers ||=
    if superclass.respond_to?(:retriers)
      superclass.retriers.dup
    else
      CMDx.configuration.retriers.dup
    end
end

.retry_on(*exceptions, **options) {|attempt, delay| ... } ⇒ Retry

Declares exceptions to retry on. Builds on the superclass’s ‘Retry`. Passing no exceptions returns the current (possibly inherited) Retry.

Parameters:

  • exceptions (Array<Class>)
  • options (Hash{Symbol => Object})

Options Hash (**options):

  • :limit (Integer) — default: see {Retry#initialize}
  • :delay (Float) — default: see {Retry#initialize}
  • :max_delay (Float) — default: see {Retry#initialize}
  • :jitter (Symbol, Proc, #call) — default: see {Retry#initialize}
  • :if (Symbol, Proc, #call)

    gate ‘(task, error, attempt)` for retries

  • :unless (Symbol, Proc, #call)

    gate ‘(task, error, attempt)` for retries

Yields:

  • (attempt, delay)

    optional custom jitter block

Returns:



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/cmdx/task.rb', line 33

def retry_on(*exceptions, **options, &)
  @retry_on ||=
    if superclass.respond_to?(:retry_on)
      superclass.retry_on.build(exceptions, options, &)
    else
      Retry.new(exceptions, options, &)
    end

  return @retry_on if exceptions.empty?

  @retry_on = @retry_on.build(exceptions, options, &)
end

.settings(options = EMPTY_HASH) ⇒ Settings

Reads or extends this class’s Settings. Inherits from the superclass.

Parameters:

  • options (Hash{Symbol => Object}) (defaults to: EMPTY_HASH)

    merged onto the current settings

Options Hash (options):

  • :logger (Logger) — default: see {Settings#initialize}
  • :log_formatter (#call) — default: see {Settings#initialize}
  • :log_level (Integer) — default: see {Settings#initialize}
  • :backtrace_cleaner (#call) — default: see {Settings#initialize}
  • :log_exclusions (Array<Symbol>) — default: see {Settings#initialize}
  • :tags (Array<Symbol, String>) — default: see {Settings#initialize}
  • :strict_context (Boolean) — default: see {Settings#initialize}

Returns:



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/cmdx/task.rb', line 57

def settings(options = EMPTY_HASH)
  @settings ||=
    if superclass.respond_to?(:settings)
      superclass.settings.build(options)
    else
      Settings.new(options)
    end

  return @settings if options.empty?

  @settings = @settings.build(options)
end

.telemetryTelemetry

Returns cloned from superclass/configuration on first call.

Returns:

  • (Telemetry)

    cloned from superclass/configuration on first call



97
98
99
100
101
102
103
104
# File 'lib/cmdx/task.rb', line 97

def telemetry
  @telemetry ||=
    if superclass.respond_to?(:telemetry)
      superclass.telemetry.dup
    else
      CMDx.configuration.telemetry.dup
    end
end

.typeString

Returns ‘“Workflow”` when the class includes Workflow, else `“Task”`.

Returns:

  • (String)

    ‘“Workflow”` when the class includes Workflow, else `“Task”`



356
357
358
# File 'lib/cmdx/task.rb', line 356

def type
  @type ||= include?(Workflow) ? "Workflow" : "Task"
end

.validatorsValidators

Returns cloned from superclass/configuration on first call.

Returns:

  • (Validators)

    cloned from superclass/configuration on first call



117
118
119
120
121
122
123
124
# File 'lib/cmdx/task.rb', line 117

def validators
  @validators ||=
    if superclass.respond_to?(:validators)
      superclass.validators.dup
    else
      CMDx.configuration.validators.dup
    end
end

Instance Method Details

#execute(strict: false) {|result| ... } ⇒ Result, Object Also known as: call

Executes this task instance through Runtime.

Parameters:

  • strict (Boolean) (defaults to: false)

    when ‘true`, re-raises Fault/exceptions on failure; when `false`, swallows them and returns the Result

Yield Parameters:

Returns:

  • (Result, Object)

    the yielded block’s value when a block is given, otherwise the Result

Raises:

  • (Fault, StandardError)

    only when ‘strict: true` and the task fails



435
436
437
438
# File 'lib/cmdx/task.rb', line 435

def execute(strict: false)
  result = Runtime.execute(self, strict:)
  block_given? ? yield(result) : result
end

#loggerLogger

Returns a logger tailored to this task’s settings.

Returns:

  • (Logger)

    a logger tailored to this task’s settings



442
443
444
# File 'lib/cmdx/task.rb', line 442

def logger
  @logger ||= LoggerProxy.logger(self)
end

#workvoid

This method is abstract.

This method returns an undefined value.

The task’s core logic. Subclasses must override.

Raises:



451
452
453
# File 'lib/cmdx/task.rb', line 451

def work
  raise ImplementationError, "undefined method #{self.class}#work"
end