AshDispatch.Workers.RetryFailedDeliveries (AshDispatch v0.5.1)

View Source

Cron worker that automatically retries failed delivery receipts.

Runs periodically via Oban.Plugins.Cron. Queries for delivery receipts that:

  • Have status == :failed (temporary failure)
  • Have retry_count < max_retries (default: 5)
  • Either haven't been retried yet OR last retry was > retry_delay_minutes ago
  • Are not permanently failed (:failed_permanent)

For each eligible receipt:

  1. Re-enqueues appropriate Oban worker (SendEmail for now)
  2. Updates receipt status to :scheduled
  3. Increments retry_count
  4. Sets last_retry_at timestamp

If a receipt has hit max_retries, it will be marked as :failed_permanent by the SendEmail worker on the final attempt.

Configuration

Configure retry behavior:

config :ash_dispatch,
  max_retries: 5,              # Max retry attempts before permanent failure
  retry_delay_minutes: 15      # Minutes to wait between retries

Scheduling

Add to Oban cron config:

config :my_app, Oban,
  plugins: [
    {Oban.Plugins.Cron,
     crontab: [
       # Retry failed deliveries every 15 minutes
       {"*/15 * * * *", AshDispatch.Workers.RetryFailedDeliveries}
     ]}
  ]

Exponential Backoff

The retry delay is constant (15 minutes by default), but you can implement exponential backoff by checking retry_count in the worker:

# Custom delay based on retry count
delay_minutes = retry_delay_minutes * (2 ** retry_count)

Example Output

[info] RetryFailedDeliveries: Found 3 failed deliveries to retry
[info] Retried delivery: receipt_id=abc123, event=order.created, transport=email, retry_count=2
[info] Retry results: 3 succeeded, 0 failed

Monitoring

Track retry metrics in your monitoring system:

  • Number of failed receipts retried per run
  • Success/failure rate of retries
  • Receipts hitting max_retries (becoming :failed_permanent)

Summary

Functions

Processes the retry job.

Retry a single failed delivery receipt.

Functions

perform(job)

Processes the retry job.

Queries for eligible failed receipts and retries them.

Returns

  • :ok on success (even if individual retries fail)
  • {:error, reason} if the query itself fails

retry_receipt(receipt, max_retries)

Retry a single failed delivery receipt.

Re-enqueues the appropriate worker based on transport and updates receipt state.

Parameters

  • receipt - DeliveryReceipt struct to retry
  • max_retries - Maximum number of retries allowed

Returns

  • :ok on success
  • {:error, reason} on failure