🏠 Home 👤 About ⚡ Skills 💼 Portfolio 📦 Packages 📝 Blog ✉ Contact ✉ Contact Now
All Articles

Laravel Queues in Production: Jobs, Failures and the Things That Bite

Moving work to a queue is easy. Keeping that queue healthy at 3am when a third-party API is down is the part nobody writes about.

Junaid Ali 2 min read 0 views

Every slow request is a queue job waiting to happen. Sending email, generating a PDF, calling a payment provider, resizing an upload — none of that belongs in the request cycle. Moving it out is the easy part.

Make Every Job Idempotent

A job will run twice. Not might — will. A worker gets killed mid-execution, the job returns to the queue, and it runs again. If your job charges a card, that is a real problem.

public function handle(): void
{
    if ($this->order->fresh()->is_paid) {
        return; // already handled by an earlier attempt
    }

    $this->chargeCard();
}

Set Retries and Backoff Deliberately

The defaults are rarely what you want. A job hitting a rate-limited API should back off exponentially, not hammer it three times in a second.

public $tries = 5;
public $backoff = [10, 30, 120, 600];
public $timeout = 60;

Watch the failed_jobs Table

Laravel writes every permanently failed job to failed_jobs. In most projects I audit, nobody has ever looked at it. Run php artisan queue:failed and you often find a year of silently dropped emails.

Send yourself an alert on failure:

public function failed(Throwable $e): void
{
    Log::error('Payment job failed', ['order' => $this->order->id, 'error' => $e->getMessage()]);
}

Supervisor, Not nohup

A worker process will die. Supervisor restarts it. Without a process manager, your queue stops silently and nothing tells you.

[program:laravel-worker]
command=php /var/www/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
numprocs=2

Always Restart Workers on Deploy

Workers hold your code in memory. Deploying new code without php artisan queue:restart means jobs keep running the old version — a genuinely confusing bug to chase.

What to Monitor

  • Queue depth — a number that only goes up means workers are dead or too slow.
  • Failed job count in the last hour.
  • Oldest pending job age — better signal than depth alone.
Tagged Laravel Queues Production Reliability
Share this article

Want this built properly?

I take on a small number of projects at a time so each one gets real attention.

WhatsApp Teams LinkedIn Facebook GitHub