Class: ActiveJob::Temporal::RetryHandlerExtractor

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

Overview

Note:

ActiveJob Compatibility ActiveJob does not expose retry_on or discard_on metadata through a public API. If retry metadata cannot be read, the extractor logs a warning and returns nil retry values so RetryMapper can use configured defaults instead of failing during enqueue.

Extracts ActiveJob retry_on and discard_on handler declarations.

This class introspects an ActiveJob class to find all retry_on and discard_on declarations, converting them into structured handler objects. It handles the complexity of ActiveJob’s internal rescue_handlers mechanism, including binding inspection and exception class constantization.

The extractor is used by RetryMapper to separate handler extraction logic from retry policy building logic, improving testability and maintainability.

rubocop:disable Metrics/ClassLength

Examples:

Extracting retry handlers

extractor = RetryHandlerExtractor.new
retry_handlers = extractor.retry_handlers(MyJob)
# => [{ exception: StandardError, wait: 5.seconds, attempts: 3, handler: ... }]

Extracting discard handlers

discard_handlers = extractor.discard_handlers(MyJob)
# => [{ exception: ActiveRecord::RecordNotFound, handler: ... }]

Instance Method Summary collapse

Constructor Details

#initializeRetryHandlerExtractor

Returns a new instance of RetryHandlerExtractor.



35
36
37
38
39
# File 'lib/activejob/temporal/retry_handler_extractor.rb', line 35

def initialize
  @cache_mutex = Mutex.new
  @retry_handlers_by_job_class = ObjectSpace::WeakMap.new
  @discard_handlers_by_job_class = ObjectSpace::WeakMap.new
end

Instance Method Details

#discard_exception?(job_class, exception) ⇒ Boolean

Checks if an exception should be discarded based on job class handlers.

Inspects the job class’s discard_on declarations to determine if the given exception matches any discard handler. This is used to determine if an activity should raise a non-retryable error in Temporal.

Examples:

Check if exception is discardable

class MyJob < ApplicationJob
  discard_on ActiveRecord::RecordNotFound
end

extractor = RetryHandlerExtractor.new
extractor.discard_exception?(MyJob, ActiveRecord::RecordNotFound.new)
# => true

Parameters:

  • job_class (Class)

    ActiveJob class with discard_on declarations

  • exception (Exception)

    Exception instance to check

Returns:

  • (Boolean)

    true if exception should be discarded, false otherwise



118
119
120
121
122
123
124
# File 'lib/activejob/temporal/retry_handler_extractor.rb', line 118

def discard_exception?(job_class, exception)
  return false unless job_class && exception

  discard_handlers(job_class).any? do |handler|
    handles_exception?(handler[:exception], exception)
  end
end

#discard_handlers(job_class) ⇒ Array<Hash>

Extracts discard handler entries from a job class’s rescue_handlers.

Iterates through the job class’s rescue_handlers and filters for discard_on declarations. Returns structured handler entries with exception classes that should not be retried.

Examples:

Basic discard handler

class MyJob < ActiveJob::Base
  discard_on ActiveRecord::RecordNotFound
end

extractor = RetryHandlerExtractor.new
handlers = extractor.discard_handlers(MyJob)
# => [{ exception: ActiveRecord::RecordNotFound, handler: #<Proc> }]

Parameters:

  • job_class (Class)

    ActiveJob class with discard_on declarations

Returns:

  • (Array<Hash>)

    Array of discard handler entries, each containing:

    • :exception [Class] Exception class to discard (not retry)

    • :handler [Proc] The raw handler proc from ActiveJob



91
92
93
94
95
96
97
# File 'lib/activejob/temporal/retry_handler_extractor.rb', line 91

def discard_handlers(job_class)
  cached_handler_entries(@discard_handlers_by_job_class, job_class) do |handlers|
    handler_entries(job_class, handlers) do |class_or_name, handler|
      discard_handler_payload(job_class, class_or_name, handler)
    end
  end
end

#retry_handlers(job_class) ⇒ Array<Hash>

Extracts retry handler entries from a job class’s rescue_handlers.

Iterates through the job class’s rescue_handlers and filters for retry_on declarations. Binding metadata is used when available; source-location fallback keeps enqueue working if ActiveJob changes closure locals.

Examples:

Basic retry handler

class MyJob < ActiveJob::Base
  retry_on StandardError, wait: 5.seconds, attempts: 3
end

extractor = RetryHandlerExtractor.new
handlers = extractor.retry_handlers(MyJob)
# => [{ exception: StandardError, wait: 5.0, attempts: 3, handler: #<Proc> }]

Parameters:

  • job_class (Class)

    ActiveJob class with retry_on declarations

Returns:

  • (Array<Hash>)

    Array of retry handler entries, each containing:

    • :exception [Class] Exception class to match

    • :wait [Numeric, Symbol, Proc] Wait strategy (duration, :exponentially_longer, etc.)

    • :attempts [Integer, Symbol] Max attempts (number or :unlimited)

    • :handler [Proc] The raw handler proc from ActiveJob



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

def retry_handlers(job_class)
  cached_handler_entries(@retry_handlers_by_job_class, job_class) do |handlers|
    handler_entries(job_class, handlers) do |class_or_name, handler|
      retry_handler_payload(job_class, class_or_name, handler)
    end
  end
end