mule/runtime/executor

Types

Mirrors the executor.ex struct’s error fields: kind defaults to KindError (like kind: :error), error is the structured exception analog (not the persisted record — job.format_attempt flattens it at ack time), stacktrace the formatted frames of a rescued crash.

pub type Executor {
  Executor(
    job: job.Job,
    config: config.Config,
    worker: option.Option(worker.ErasedWorker),
    state: State,
    kind: exceptions.Kind,
    error: option.Option(exceptions.ExecutionError),
    stacktrace: List(String),
    result: option.Option(worker.WorkerResult),
    snooze: option.Option(duration.Duration),
    timer: option.Option(Timer),
    start_mono: Int,
    safe: Bool,
    ack: Bool,
    raw_crash: option.Option(rescue.RawCrash),
  )
}

Constructors

pub type State {
  Unset
  Success
  Failure
  Cancelled
  Discard
  Snoozed
  Exhausted
}

Constructors

  • Unset
  • Success
  • Failure
  • Cancelled
  • Discard
  • Snoozed
  • Exhausted

The reason start_timeout arms timer:exit_after with. Its compiled tuple shape ({timeout_reason, Worker, Timeout}) is pattern-matched by mule_rescue_ffi:classify_exit_reason/1, so the producer’s DOWN handler can tell a timeout from any other crash.

pub type TimeoutReason {
  TimeoutReason(worker: String, timeout: Int)
}

Constructors

  • TimeoutReason(worker: String, timeout: Int)
pub type Timer

Values

pub fn ack_event(exec: Executor) -> Executor

Ack the terminal state to the engine. Every call rides backoff.with_retry (infinite exponential+jitter on EngineFailures and crashes — Elixir’s DB-resilience wrapper). A returned Error(JobNotFound) is dropped silently: the typed equivalent of Elixir’s 0-row update_all returning :ok (the row was deleted mid-run). Run record_unsaved first — the Failure/Discard/Cancelled branches persist job.format_attempt. ack: False (the testing no-persistence path) skips everything.

pub fn call(exec: Executor) -> Executor
pub fn cancel_timeout(exec: Executor) -> Executor
pub fn new(config: config.Config, job: job.Job) -> Executor
pub fn normalize_state(exec: Executor) -> Executor
pub fn perform(exec: Executor) -> Executor
pub fn record_unsaved(exec: Executor) -> Executor

executor.ex record_unsaved/1: stamp %{kind, reason, stacktrace} onto the job before acking, so the worker’s backoff and the engine see it.

pub fn report(exec: Executor) -> Executor

Emit the terminal job event from the executor’s own process, after the ack. Success/Cancelled/Snoozed/Discard are a :stop — a manual Discarded return is the worker’s own choice, not an error (executor.ex emit_event puts :discard in the stop clause); Failure/Exhausted are an :exception, with Exhausted reported under the Discard outcome (Elixir remaps :exhausted to :discard in the metadata). The producer’s recovery / cancellation paths end in this too, so every execution — golden path, crash, pkill — reports exactly once.

pub fn reraise_unsafe(exec: Executor) -> Executor

executor.ex reraise_unsafe/1: when unsafe and perform rescued a crash, re-raise it with its original kind/reason/stacktrace — AFTER the ack and report, matching Elixir’s record_unsaved → ack_event → emit_event order (so an unsafe drain acks the failure first, then re-raises). The raw_crash-only trigger is executor.ex’s stacktrace: [_ | _] guard: only caught crashes re-raise; a worker’s returned Failed(...) completes normally.

pub fn resolve_worker(exec: Executor) -> Executor
pub fn start_timeout(exec: Executor) -> Executor
pub fn synthesize_cancellation(
  exec: Executor,
  reason reason: String,
) -> Executor

Producer backstop: a pkill/shutdown-terminated job becomes a cancellation (producer.ex:96-100’s {:cancel, :shutdown} wrapped in PerformError).

pub fn synthesize_crash(
  exec: Executor,
  reason reason: String,
  stacktrace stacktrace: List(String),
) -> Executor

Producer backstop: the job process died from an exit signal (producer.ex:102-106, kind {:EXIT, pid} normalized to :exit).

pub fn synthesize_timeout(
  exec: Executor,
  worker worker: String,
  timeout timeout: Int,
) -> Executor

Producer backstop: the timeout timer’s exit signal killed the job process (producer.ex:93-94 matching %TimeoutError{}).

Search Document