{
  "id": 20005143,
  "title": "Laravel Jobs & Queues: Retry, Backoff, Failed Jobs & Idempotency",
  "url": "https://urgent.news/2026/11/14/laravel-jobs-queues-retry-backoff-failed-jobs-idempotency",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-11-14T15:59:56.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/itxshakil/laravel-jobs-queues-retry-backoff-failed-jobs-idempotency-4a7h"
  },
  "original_language": "en",
  "account": "When working with Laravel jobs and queues, it is crucial to understand the various settings and configurations that help manage retries, backoff, failed jobs, and idempotency. This article will cover these topics in detail, explaining when and how to use them.\n\nLaravel provides several settings for configuring jobs and queues, including $tries, $backoff, $timeout, and retryUntil(). Each of these settings plays a distinct role in controlling the behavior of jobs:\n\n- $tries: This setting determines the maximum number of attempts a job can make before being moved to the failed_jobs table. The job property always takes precedence over the worker flag.\n\n- $backoff: This setting specifies the delay in seconds between retries after an exception occurs. It can be an array to set a delay per attempt, with the last value repeating for any remaining attempts.\n\n- $timeout: This setting defines the maximum time a job can run before being killed by the worker. It must be shorter than the connection's retry_after value to prevent duplicate runs of the job.\n\n- retryUntil(): This setting defines a deadline for a job, causing it to retry until this time is reached, thereby ignoring the $tries setting. It is useful when a deadline is more critical than the number of attempts.\n\nAdditionally, $maxExceptions and $timeout settings are available for handling unhandled exceptions and job timeouts, respectively.\n\nWhen setting up jobs and queues, it is essential to ensure the $timeout value is shorter than the retry_after value in the config/queue.php file. This ensures duplicate runs of the job are prevented.\n\nTo handle failed jobs, you can use the following commands:\n\n- php artisan queue:failed: This command lists all failed jobs with their UUIDs.\n- php artisan queue:retry {uuid}: This command retries a single failed job using its UUID.\n- php artisan queue:retry all: This command retries all failed jobs.\n- php artisan queue:retry --queue=emails: This command retries failed jobs from a specific queue.\n- php artisan queue:forget {uuid}: This command deletes a failed job using its UUID.\n- php artisan queue:prune-failed --hours=48: This command removes failed jobs older than 48 hours.\n\nBefore using the queue:retry all command, it is essential to fix the underlying cause of the failures, as mass-retry might simply refill the failed_jobs table.\n\nTo ensure idempotency and make retries safe, consider the following strategies:\n\n1. Check for existing state before performing any side effects (e.g., charging a card or sending an email).\n2. Enforce idempotency using a unique index on an idempotency key or implementing the ShouldBeUnique interface.\n3. Prevent concurrent runs by using the WithoutOverlapping middleware, keyed by record ID.\n\nBy understanding and applying these settings and configurations, you can effectively manage Laravel jobs and queues, ensuring robust, reliable, and efficient processing of your application's background tasks.",
  "summary": "Series: Every Laravel Project Should Have These Building Blocks Part: 15 of 35 Level: Intermediate Prerequisites: Action Classes What You’ll Learn When to use a Job vs. a queued Event Listener The anatomy of a well-written Job class Retry configuration, backoff strategies, and failure handling The HeartBeat pattern — checking queue health on a schedule Unique jobs and idempotency Named queues and…",
  "key_points": [
    "$tries limits job attempts before moving to failedjobs table",
    "$backoff delays retries after exceptions, can be per-attempt array",
    "$timeout kills job if exceeds set time limit"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}