Skip to content

Add opt-in retry mechanism to QueueableJob` #34

Description

@Mateusz7410

Problem

Queueables routinely fail on transient errors (UNABLE_TO_LOCK_ROW, callout timeouts, QUERY_TIMEOUT) that would succeed on retry. Today each consumer reimplements retry ad-hoc or doesn't bother — failures hit Log__c and require manual replay.

Proposal

Opt-in retry config on Async.queueable(...). Defaults must be off to avoid surprise retries on non-idempotent jobs. Global defaults configurable via custom metadata / settings, but every job still has to flip the switch explicitly.

Async.queueable(new MyJob(args))
    .withRetry(3)
    .withBackoff(Async.Backoff.exponential(5))    // 5s, 10s, 20s
    .retryOn(DmlException.class, CalloutException.class)
    .enqueue();

Design

  • Implemented via existing finalizer hook on QueueableJob
  • Finalizer inspects Result.getException() — if class matches whitelist AND attempt < max → re-enqueue deep-clone with attempt++ and computed delay
  • On exhaustion → single Log__c row aggregating all attempts (attempt #, delay, exception per try) — not one row per failed try

Open Questions

  • Where should attempt counter live — job state field on the subclass, or framework-managed sidecar invisible to subclasses?
  • Should we ship a curated default whitelist of "always-safe-to-retry" exceptions (UNABLE_TO_LOCK_ROW, 5xx CalloutException) that dev can pull in via .withDefaultRetryableExceptions()?
  • Settings-level global defaults — custom metadata (AsyncRetryConfig__mdt) keyed by job class?

Acceptance Criteria

  • Default = no retry (backward compatible, no implicit side effects)
  • Per-job opt-in via fluent API
  • Backoff strategies: fixed, exponential, exponentialWithJitter
  • Exception whitelist API (retryOn(...))
  • Configurable max attempts with framework-level safety cap
  • Docs in Async-lib README

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions