Class: ActiveJob::Temporal::WorkflowIdBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/activejob/temporal/workflow_id_builder.rb

Overview

Builds deterministic Temporal workflow IDs for ActiveJob jobs.

The default format keeps workflow IDs stable across enqueue retries so Temporal can reject duplicate starts for the same ActiveJob job_id.

Constant Summary collapse

DEFAULT_PREFIX =
"ajwf"
MAX_WORKFLOW_ID_LENGTH =
255
CONTROL_CHARACTER_PATTERN =
/[[:cntrl:]]/

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(strategy = nil) ⇒ WorkflowIdBuilder

Returns a new instance of WorkflowIdBuilder.

Parameters:

  • strategy (#call, nil) (defaults to: nil)

    Optional callable that receives the job and returns a workflow ID



17
18
19
# File 'lib/activejob/temporal/workflow_id_builder.rb', line 17

def initialize(strategy = nil)
  @strategy = strategy
end

Class Method Details

.default_for(job) ⇒ String

Builds the default workflow ID for a job.

Parameters:

  • job (ActiveJob::Base)

    ActiveJob instance being enqueued

Returns:

  • (String)

    Workflow ID in format “ajwf:<ClassName>:<job_id>”



50
51
52
# File 'lib/activejob/temporal/workflow_id_builder.rb', line 50

def default_for(job)
  default_from_job_class(job.class, job.job_id)
end

.default_from_job_class(job_class, job_id) ⇒ String

Builds the default workflow ID from a job class and job ID.

Parameters:

  • job_class (Class)

    ActiveJob class

  • job_id (String)

    ActiveJob job_id

Returns:

  • (String)

    Workflow ID in format “ajwf:<ClassName>:<job_id>”



59
60
61
# File 'lib/activejob/temporal/workflow_id_builder.rb', line 59

def default_from_job_class(job_class, job_id)
  "#{DEFAULT_PREFIX}:#{job_class.name}:#{job_id}"
end

.prefixed_from_job_class(job_class, job_id) ⇒ Object



63
64
65
66
67
68
# File 'lib/activejob/temporal/workflow_id_builder.rb', line 63

def prefixed_from_job_class(job_class, job_id)
  prefix = workflow_id_prefix_for(job_class)
  return unless prefix

  "#{prefix}:#{job_id}"
end

.validate!(workflow_id) ⇒ void

This method returns an undefined value.

Validates generated workflow IDs before they reach Temporal.

Parameters:

  • workflow_id (Object)

    generated workflow ID

Raises:



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/activejob/temporal/workflow_id_builder.rb', line 81

def validate!(workflow_id)
  unless workflow_id.is_a?(String)
    raise ConfigurationError,
          "workflow_id_generator must return a String, got #{workflow_id.class}: #{workflow_id.inspect}"
  end

  if workflow_id.empty?
    raise ConfigurationError, "workflow_id_generator returned an invalid workflow ID: must not be blank"
  end

  unless utf8_compatible?(workflow_id)
    raise ConfigurationError,
          "workflow_id_generator returned an invalid workflow ID: must be valid UTF-8"
  end

  if workflow_id.length > MAX_WORKFLOW_ID_LENGTH
    raise ConfigurationError,
          "workflow_id_generator returned an invalid workflow ID: maximum length is " \
          "#{MAX_WORKFLOW_ID_LENGTH} characters (got #{workflow_id.length})"
  end

  return unless workflow_id.match?(CONTROL_CHARACTER_PATTERN)

  raise ConfigurationError,
        "workflow_id_generator returned an invalid workflow ID: control characters are not allowed " \
        "(got #{workflow_id.inspect})"
end

.workflow_id_prefix_for(job_class) ⇒ Object



70
71
72
73
74
# File 'lib/activejob/temporal/workflow_id_builder.rb', line 70

def workflow_id_prefix_for(job_class)
  return unless job_class.respond_to?(:temporal_workflow_id_prefix)

  job_class.temporal_workflow_id_prefix
end

Instance Method Details

#build(job) ⇒ String

Builds a workflow ID from an ActiveJob instance.

Parameters:

  • job (ActiveJob::Base)

    ActiveJob instance being enqueued

Returns:

  • (String)

    Workflow ID in format “ajwf:<ClassName>:<job_id>”



25
26
27
28
29
30
31
# File 'lib/activejob/temporal/workflow_id_builder.rb', line 25

def build(job)
  workflow_id = class_configured_workflow_id(job) ||
                configured_workflow_id(job) ||
                self.class.default_for(job)
  self.class.validate!(workflow_id)
  workflow_id
end

#build_from_job_class(job_class, job_id) ⇒ String

Builds a workflow ID from a job class and job ID.

Parameters:

  • job_class (Class)

    ActiveJob class

  • job_id (String)

    ActiveJob job_id

Returns:

  • (String)

    Workflow ID in format “ajwf:<ClassName>:<job_id>”



38
39
40
41
42
43
# File 'lib/activejob/temporal/workflow_id_builder.rb', line 38

def build_from_job_class(job_class, job_id)
  workflow_id = self.class.prefixed_from_job_class(job_class, job_id) ||
                self.class.default_from_job_class(job_class, job_id)
  self.class.validate!(workflow_id)
  workflow_id
end