Laravel Queues and Jobs (with Failure Handling)

Introduction to Queues

Queues allow you to defer time-consuming tasks (like sending emails or processing files) to be executed in the background, improving your application's response time.

Creating Jobs

Generate a new job:

bash
php artisan make:job ProcessPodcast

Basic job structure:

php
<?php

namespace App\Jobs;

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

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

    protected $podcast;

    public function __construct($podcast)
    {
        $this->podcast = $podcast;
    }

    public function handle()
    {
        // Process the podcast...
    }
}

Dispatching Jobs

Synchronous dispatch (for testing):

php
ProcessPodcast::dispatch($podcast)->onConnection('sync');

Asynchronous dispatch:

php
// Basic dispatch
ProcessPodcast::dispatch($podcast);

// Delayed dispatch (5 minutes)
ProcessPodcast::dispatch($podcast)->delay(now()->addMinutes(5));

// Specific queue
ProcessPodcast::dispatch($podcast)->onQueue('processing');

Queue Configuration

.env configuration:

env
QUEUE_CONNECTION=database # or redis, sqs, beanstalkd, etc.

Configuring queue workers (in config/queue.php):

php
'connections' => [
    'database' => [
        'driver' => 'database',
        'table' => 'jobs',
        'queue' => 'default',
        'retry_after' => 90,
    ],
],

Running Queue Workers

Start a basic worker:

bash
php artisan queue:work

Options:

bash
# Process a specific queue
php artisan queue:work --queue=high,default

# Process only one job (good for debugging)
php artisan queue:work --once

# Process with maximum time/memory limits
php artisan queue:work --max-time=3600 --memory=128

# Run in daemon mode (using Supervisor recommended)
php artisan queue:work --daemon

Failure Handling

Failed Jobs Table

Create failed jobs table:

bash
php artisan queue:failed-table
php artisan migrate

Handling Job Failures

1. Maximum Attempts:

php
public $tries = 3; // Maximum number of attempts

2. Timeout:

php
public $timeout = 120; // Job timeout in seconds

3. Retry Until:

php
public function retryUntil()
{
    return now()->addMinutes(10);
}

4. Failed Method:

php
public function failed(Exception $exception)
{
    // Send notification, log, etc.
}

Managing Failed Jobs

List failed jobs:

bash
php artisan queue:failed

Retry failed jobs:

bash
# Retry all failed jobs
php artisan queue:retry all

# Retry specific failed jobs
php artisan queue:retry 1 2 3

Delete failed jobs:

bash
# Delete a specific failed job
php artisan queue:forget 5

# Delete all failed jobs
php artisan queue:flush

Queue Priorities

Dispatching to different queues:

php
// High priority job
ProcessPodcast::dispatch($podcast)->onQueue('high');

// Low priority job
ProcessPodcast::dispatch($podcast)->onQueue('low');

Processing with priorities:

bash
php artisan queue:work --queue=high,low

Testing Jobs

Test if job was dispatched:

php
// In your test
Bus::fake();

// Perform action that should dispatch job
Bus::assertDispatched(ProcessPodcast::class);

// Or assert it wasn't dispatched
Bus::assertNotDispatched(ProcessPodcast::class);

Best Practices

  1. Always use SerializesModels trait when working with Eloquent models

  2. Keep job payloads small (store data in DB and pass IDs if needed)

  3. Use Supervisor to keep queue workers running

  4. Set appropriate timeout and retry values

  5. Monitor your failed jobs regularly

  6. Consider using Horizon for Redis queues in production

To Top