Class: GenevaDrive::StepExecution

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
MetadataAccessor
Defined in:
lib/geneva_drive/step_execution.rb

Overview

Represents a single step execution attempt within a workflow. Serves as both an audit record and an idempotency key.

Each step execution tracks:

  • The step being executed
  • The current state of execution
  • When the step was scheduled, started, and completed
  • Any errors that occurred
  • The outcome of the execution

Examples:

Querying step executions

workflow.step_executions.completed.each do |exec|
  puts "#{exec.step_name}: #{exec.outcome}"
end

Defined Under Namespace

Modules: MetadataAccessor

Constant Summary collapse

OUTCOMES =

Outcome values for audit purposes

%w[
  success
  reattempted
  skipped
  canceled
  failed
  recovered
  workflow_paused
].freeze

Instance Method Summary collapse

Methods included from MetadataAccessor

#exception_info, #read_metadata, #reattempt_reason, #write_metadata

Instance Method Details

#execute!void

This method returns an undefined value.

Executes this step using the Executor.



149
150
151
# File 'lib/geneva_drive/step_execution.rb', line 149

def execute!
  GenevaDrive::Executor.execute!(self)
end

#loggerLogger

Same as ActiveRecord::Base#logger but supplemented with tags for step and workflow

Returns:

  • (Logger)


156
157
158
159
160
161
# File 'lib/geneva_drive/step_execution.rb', line 156

def logger
  @logger ||= begin
    workflow_tagged_logger = workflow.logger
    workflow_tagged_logger.tagged("execution_id=#{id} step_name=#{step_name}")
  end
end

#mark_canceled!(outcome: "canceled") ⇒ void

This method returns an undefined value.

Marks the step execution as canceled.

Parameters:

  • outcome (String) (defaults to: "canceled")

    the outcome (defaults to 'canceled')



129
130
131
132
133
134
135
136
137
# File 'lib/geneva_drive/step_execution.rb', line 129

def mark_canceled!(outcome: "canceled")
  with_lock do
    update!(
      state: "canceled",
      canceled_at: Time.current,
      outcome: outcome
    )
  end
end

#mark_completed!(outcome: "success") ⇒ void

This method returns an undefined value.

Marks the step execution as completed.

Parameters:

  • outcome (String) (defaults to: "success")

    the outcome ('success' or 'reattempted')



82
83
84
85
86
87
88
89
90
# File 'lib/geneva_drive/step_execution.rb', line 82

def mark_completed!(outcome: "success")
  with_lock do
    update!(
      state: "completed",
      completed_at: Time.current,
      outcome: outcome
    )
  end
end

#mark_failed!(error, outcome: "failed") ⇒ void

This method returns an undefined value.

Marks the step execution as failed and records the error.

Parameters:

  • error (Exception)

    the error that occurred

  • outcome (String) (defaults to: "failed")

    the outcome ('failed' or 'canceled')



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/geneva_drive/step_execution.rb', line 97

def mark_failed!(error, outcome: "failed")
  with_lock do
    attrs = {
      state: "failed",
      failed_at: Time.current,
      outcome: outcome,
      error_message: error.message,
      error_backtrace: error.backtrace&.join("\n")
    }
    attrs[:error_class_name] = error.class.name if has_attribute?(:error_class_name)
    update!(attrs)
  end
end

#mark_skipped!(outcome: "skipped") ⇒ void

This method returns an undefined value.

Marks the step execution as skipped.

Parameters:

  • outcome (String) (defaults to: "skipped")

    the outcome (defaults to 'skipped')



115
116
117
118
119
120
121
122
123
# File 'lib/geneva_drive/step_execution.rb', line 115

def mark_skipped!(outcome: "skipped")
  with_lock do
    update!(
      state: "skipped",
      skipped_at: Time.current,
      outcome: outcome
    )
  end
end

#start!Boolean

Transitions the step execution to 'in_progress' state. Uses pessimistic locking to prevent double execution.

Returns:

  • (Boolean)

    true if transition succeeded, false if already executed



67
68
69
70
71
72
73
74
75
76
# File 'lib/geneva_drive/step_execution.rb', line 67

def start!
  with_lock do
    return false unless scheduled?
    update!(
      state: "in_progress",
      started_at: Time.current
    )
  end
  true
end

#step_definitionStepDefinition?

Returns the step definition for this execution.

Returns:



142
143
144
# File 'lib/geneva_drive/step_execution.rb', line 142

def step_definition
  workflow.class.steps.named(step_name)
end

#with_logger(logger) { ... } ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Temporarily overrides the step execution's logger for the duration of the block. The passed logger is used directly - it should already include step-specific tags. The original logger is restored after the block completes.

Parameters:

  • logger (Logger)

    the logger to use (already fully tagged)

Yields:

  • the block to execute with the injected logger

Returns:

  • (Object)

    the result of the block



171
172
173
174
175
176
177
# File 'lib/geneva_drive/step_execution.rb', line 171

def with_logger(logger)
  previous_logger = @logger
  @logger = logger
  yield
ensure
  @logger = previous_logger
end