Bird
Raised Fist0
Laravelframework~5 mins

Job retries and failure in Laravel

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction

Sometimes jobs in Laravel fail or need to be tried again. Job retries help automatically try a job again if it fails. Handling failures lets you manage what happens when retries stop.

When sending emails that might fail due to temporary network issues.
When processing payments that could fail and need retrying.
When importing data from an external API that might be temporarily down.
When running background tasks that should not stop on first error.
When you want to log or notify when a job finally fails after retries.
Syntax
Laravel
class ExampleJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $tries = 5; // Number of retry attempts
    public $timeout = 120; // Max seconds before job times out

    public function handle()
    {
        // Job logic here
    }

    public function failed(Exception $exception)
    {
        // Logic when job fails after all retries
    }
}

The $tries property sets how many times Laravel will retry the job before failing.

The failed() method runs only after all retries fail, letting you handle cleanup or notifications.

Examples
This job will try 3 times before calling failed().
Laravel
class SendEmailJob implements ShouldQueue
{
    public $tries = 3;

    public function handle()
    {
        // Send email logic
    }

    public function failed(Exception $exception)
    {
        // Notify admin about failure
    }
}
This job will not retry and will call failed() immediately on failure.
Laravel
class ProcessPaymentJob implements ShouldQueue
{
    public $tries = 1; // No retries

    public function handle()
    {
        // Payment processing
    }

    public function failed(Exception $exception)
    {
        // Log failure
    }
}
Setting $tries = null means Laravel will keep retrying forever until success.
Laravel
class ImportDataJob implements ShouldQueue
{
    public $tries = null; // Infinite retries (not recommended)

    public function handle()
    {
        // Data import
    }
}
Sample Program

This example simulates a job that always fails. It tries 3 times, printing each attempt. After the last failure, it calls the failed() method to show the final failure message.

Laravel
<?php

namespace App\Jobs;

use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ExampleJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $tries = 3;

    public function handle()
    {
        echo "Trying job...\n";
        // Simulate failure
        throw new Exception("Job failed");
    }

    public function failed(Exception $exception)
    {
        echo "Job failed after retries: " . $exception->getMessage() . "\n";
    }
}

// Simulate running the job manually for demonstration
$job = new ExampleJob();

for ($attempt = 1; $attempt <= $job->tries; $attempt++) {
    try {
        echo "Attempt $attempt:\n";
        $job->handle();
        break; // If success, stop retrying
    } catch (Exception $e) {
        echo "Caught exception: " . $e->getMessage() . "\n";
        if ($attempt === $job->tries) {
            $job->failed($e);
        }
    }
}
OutputSuccess
Important Notes

Time complexity: Job retries depend on external factors, but each retry runs the job logic once.

Space complexity: Minimal, mostly storing job data and retry count.

Common mistake: Forgetting to set $tries means Laravel uses default retries, which might be unexpected.

Use retries when failures are temporary. Use failed() to handle permanent failures like logging or alerts.

Summary

Set $tries in your job to control retry attempts.

Use the failed() method to handle what happens after all retries fail.

Retries help jobs recover from temporary problems without manual intervention.

Practice

(1/5)
1. In Laravel, what does setting the $tries property in a job class control?
easy
A. The number of times the job will be retried if it fails
B. The maximum execution time of the job
C. The priority of the job in the queue
D. The database connection used by the job

Solution

  1. Step 1: Understand the role of $tries in Laravel jobs

    The $tries property defines how many times Laravel will attempt to run the job if it fails.
  2. Step 2: Differentiate from other job properties

    It does not control execution time, priority, or database connection, only retry attempts.
  3. Final Answer:

    The number of times the job will be retried if it fails -> Option A
  4. Quick Check:

    $tries controls retry attempts [OK]
Hint: Remember: $tries means retry count for failed jobs [OK]
Common Mistakes:
  • Confusing $tries with job timeout
  • Thinking $tries sets job priority
  • Assuming $tries controls database connection
2. Which of the following is the correct way to define a job retry limit of 5 attempts in a Laravel job class?
easy
A. public $tries = 5;
B. protected $retry = 5;
C. public $retryAttempts = 5;
D. protected $triesCount = 5;

Solution

  1. Step 1: Recall the correct property name for retry attempts

    Laravel uses $tries as a public property to set retry limits.
  2. Step 2: Check syntax and visibility

    The property should be public and named exactly $tries to work properly.
  3. Final Answer:

    public $tries = 5; -> Option A
  4. Quick Check:

    Correct property is public $tries [OK]
Hint: Use public $tries = number; to set retries [OK]
Common Mistakes:
  • Using protected instead of public
  • Using wrong property names like $retry or $triesCount
  • Confusing retry limit with timeout
3. Given this Laravel job class snippet:
class SendEmailJob implements ShouldQueue {
    public $tries = 3;
    public function handle() {
        // code that may fail
        throw new \Exception('Failed');
    }
    public function failed() {
        // handle failure
        Log::info('Job failed permanently');
    }
}

How many times will Laravel attempt to run this job before calling failed()?
medium
A. 1 time
B. 3 times
C. 4 times
D. It will retry indefinitely

Solution

  1. Step 1: Understand how $tries works

    The $tries property sets the maximum number of times the job will be attempted, including the initial attempt.
  2. Step 2: Calculate total attempts

    With $tries = 3, Laravel attempts the job 3 times total before calling failed().
  3. Final Answer:

    3 times -> Option B
  4. Quick Check:

    Total attempts = $tries = 3 [OK]
Hint: Total attempts = $tries [OK]
Common Mistakes:
  • Thinking total attempts = 1 + $tries
  • Assuming retries are unlimited
  • Confusing failed() call timing
4. Examine this Laravel job code:
class ProcessOrder implements ShouldQueue {
    public $tries = 2;
    public function handle() {
        // some code
        throw new \Exception('Error');
    }
    public function failed() {
        // log failure
        Log::error('Order processing failed');
    }
}

Why might the failed() method never be called after job failures?
medium
A. Because the $tries property is set to 2, so it retries infinitely
B. Because the job is not implementing the ShouldQueue interface
C. Because the job is failing but failed() is not triggered until retries are exhausted
D. Because the failed() method must accept an Exception parameter

Solution

  1. Step 1: Check method signature for failed()

    Laravel expects failed() to accept an Exception parameter to receive failure details.
  2. Step 2: Understand impact of missing parameter

    If failed() lacks the Exception parameter, Laravel may not call it properly after retries.
  3. Final Answer:

    The failed() method must accept an Exception parameter -> Option D
  4. Quick Check:

    failed(Exception $exception) required [OK]
Hint: Add Exception parameter to failed() method [OK]
Common Mistakes:
  • Assuming $tries = 2 means infinite retries
  • Forgetting to implement ShouldQueue interface
  • Ignoring method signature requirements
5. You want a Laravel job to retry 3 times on failure, but after the last failure, you want to notify the user by email. Which is the best way to implement this behavior?
hard
A. Set public $tries = 3; and use a separate job to send the email without failed()
B. Set public $tries = 3; and send the email inside the handle() method after catching exceptions
C. Set public $tries = 3; and define a failed(Exception $exception) method to send the email notification
D. Set public $maxAttempts = 3; and send the email in the constructor

Solution

  1. Step 1: Use $tries to limit retry attempts

    Setting public $tries = 3; ensures the job retries 3 times on failure.
  2. Step 2: Use failed(Exception $exception) to handle final failure

    Defining failed() with the Exception parameter allows sending email after all retries fail.
  3. Final Answer:

    Set public $tries = 3; and define a failed(Exception $exception) method to send the email notification -> Option C
  4. Quick Check:

    Retries + failed() method for final failure handling [OK]
Hint: Use $tries and failed(Exception $exception) for retries and notification [OK]
Common Mistakes:
  • Trying to send email inside handle() ignoring retries
  • Using wrong property name like $maxAttempts
  • Not using failed() method for final failure