Plan: Implement retry policies with exponential backoff and dead-letter handling (5.2.3) - #457
Conversation
Add the execution plan for backend roadmap item 5.2.3: bounded exponential-backoff retry policies and dead-letter handling for the Apalis (PostgreSQL) queue adapter. The plan records the Apalis 1.0-rc capability research (tower-based in-process retry, no built-in dead-letter API, incomplete abort persistence at rc.6), proposes a pure domain retry policy plus a `DeadLetterQueue` port with a PostgreSQL adapter, and defines the verification obligations (rstest, proptest, rstest-bdd against embedded PostgreSQL). Status is DRAFT pending expert-panel revision and user approval. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The typos gate rejects "requeueing"; use the accepted spelling. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fold the design-review panel's findings into the plan: - Make fatal dead-lettering a storage-level action: an early fatal failure acked as `Failed` with spare attempts would otherwise be re-delivered by `apalis.get_jobs` and invisible to the dead predicate (D4 rewritten; V5 asserts non-re-delivery). - Reconcile the two retry loops (tower in-process vs storage refetch) via the named axiom AXIOM-ATTEMPT, an EP-M0 compile probe, and a total-executions assertion in V4. - Make the domain policy the executed policy by delegating a custom `tower::retry::Policy` to `JobRetryPolicy` (D1 rewritten). - Add a TOTAL_BACKOFF_BUDGET constructor constraint (V1b) and record the orphan-recovery inequality 5.3.1 must respect. - Document per-lease attempt semantics, crash-loop risk, per-attempt logging, and the fact that orphan recovery is unconfigured today. - Harden the dead-letter port: guarded compare-and-swap requeue and discard with `NotDead` errors, requeue provenance, discard as delete (D5), `DeadJobId` newtype, `dead_at`, `#[non_exhaustive]`, ordering, payload privacy, and a forbid on automated requeue. - Promote retry/dead-letter metrics to named deliverables; add rc-coupling canary tests (V8), attempt-mapping tests (V3b), an optional partial index (D6), per-instance policy (D7), an operator runbook, a harness promotion path for 5.3.1, and split the ADR into ADR-002 (retry mechanism) and ADR-003 (dead-letter representation). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Reviewer's GuidePlanning-only ExecPlan document for backend roadmap item 5.2.3, introducing a domain-level retry policy with bounded exponential backoff and jitter, a DeadLetterQueue port with a PostgreSQL adapter over apalis.jobs, storage-level fatal dead-lettering, verification strategy (unit/property/BDD/integration tests), ADRs, and documentation/runbook updates—no runtime behaviour changes yet. Sequence diagram for planned retry and fatal dead-letter handlingsequenceDiagram
participant Worker
participant JobHandler
participant JobRetryPolicy
participant RetryLayer
participant DeadLetterQueueAdapter
participant ApalisJobs
Worker->>RetryLayer: process_job()
RetryLayer->>JobHandler: handle()
JobHandler-->>RetryLayer: Err(JobErrorKind_Retryable)
RetryLayer->>JobRetryPolicy: decide(attempt, Retryable, jitter)
JobRetryPolicy-->>RetryLayer: RetryDecision_Retry(delay)
RetryLayer->>RetryLayer: wait_backoff(delay)
RetryLayer->>JobHandler: handle() (retry)
alt [fatal error]
JobHandler-->>RetryLayer: Err(JobErrorKind_Fatal)
RetryLayer->>JobRetryPolicy: decide(attempt, Fatal, jitter)
JobRetryPolicy-->>RetryLayer: RetryDecision_DeadLetter
RetryLayer->>DeadLetterQueueAdapter: mark_fatal_dead(job_id)
DeadLetterQueueAdapter->>ApalisJobs: UPDATE status = Killed
DeadLetterQueueAdapter-->>RetryLayer: Ok
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Summary
This draft pull request delivers the ExecPlan for backend roadmap item 5.2.3:
retry policies with exponential backoff and dead-letter handling for the
Apalis (PostgreSQL) queue adapter. It is a planning-only change; no
implementation begins until the plan is approved.
Plan document (branch-wise link):
docs/execplans/5-2-3-retry-policies-with-exponential-backoff-and-dead-letter-handling.md
The plan proposes:
JobRetryPolicy) computing bounded, jitteredexponential backoff under a hard total-backoff budget, with a
retryable/fatal error classification, executed in production via a
delegating
tower::retry::Policyso the verified function is the runningfunction.
DeadLetterQueuedomain port with a PostgreSQL adapter over theapalis.jobstable: ordered listing, guarded compare-and-swap requeuewith provenance, and guarded discard-as-delete.
incomplete abort-to-
Killedpath in apalis-postgres 1.0.0-rc.6.rstestunit tests,proptestinvariants,googletestand
pretty_assertionsassertions,instasnapshot stability, andrstest-bddbehavioural scenarios against embedded PostgreSQL, plusrc-coupling canary tests to catch upstream drift on the eventual 1.0-final
pin bump.
runbook, and documentation updates, with worker consumption and
deployment explicitly deferred to roadmap 5.3.1.
The draft was revised after a six-lens expert design review (structure,
contracts, scaling, operations, alternatives, and long-term viability);
the revision note at the end of the plan summarizes the changes.
References
🤖 Generated with Claude Code
Summary by Sourcery
Documentation: