Async Processing / Job Queues
debt(d7/e5/b5/t5)
Closest to 'only careful code review or runtime testing' (d7). detection_hints.automated is no; tools listed (blackfire, laravel-debugbar) are profilers that surface slow request work only when someone looks. No linter flags 'this should be async'.
Closest to 'touches multiple files / significant refactor in one component' (e5). quick_fix says move >200ms operations into a queue job, but realistically that means introducing job classes, worker infrastructure, supervisor config, and refactoring callers — more than a one-line swap, less than architectural rework.
Closest to 'persistent productivity tax' (b5). Once async is adopted, every future feature must consider sync-vs-async boundaries, payload serialization, retries, and worker ops; applies across web and queue-worker contexts but isn't the system's defining shape.
Closest to 'notable trap most devs eventually learn' (t5). The misconception (needing RabbitMQ) plus common_mistakes (no workers running, oversized payloads, no supervisor, silent failure) are well-documented gotchas — surprising to newcomers but standard knowledge once burned.
Also Known As
TL;DR
Explanation
Synchronous processing of slow operations (sending emails, resizing images, calling external APIs) directly in a web request increases response times and risks timeouts. Job queues (Laravel Queues, Symfony Messenger, RabbitMQ, Redis queues) accept a job description, store it durably, and process it asynchronously in a separate worker process. This reduces web response time to near-instant, improves resilience (failed jobs can be retried), and allows work to be distributed across multiple workers. The trade-off is eventual consistency and added infrastructure complexity.
Diagram
flowchart LR
subgraph Synchronous - Slow
REQ1[HTTP Request] --> PROC1[Process<br/>resize image<br/>5 seconds] --> RES1[Response<br/>after 5s]
end
subgraph Async - Fast
REQ2[HTTP Request] --> QUEUE[Push to Queue<br/>immediately] --> RES2[Response<br/>50ms]
QUEUE --> WORKER[Background Worker<br/>resizes image]
WORKER --> NOTIFY[Notify user<br/>when done]
end
style RES1 fill:#f85149,color:#fff
style RES2 fill:#238636,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Dispatching jobs to a queue but not running any queue workers — jobs sit queued and never process.
- Putting too much serialised data in the job payload — pass IDs and re-fetch fresh data in the worker instead.
- Not handling job failures with retries and dead-letter queues — failed jobs silently disappear.
- Running queue workers without a process supervisor (Supervisor, Horizon) — workers die and no one notices.
Code Examples
// Synchronous — user waits for email + PDF + analytics:
function placeOrder(Order $o): void {
$this->db->save($o);
$this->mailer->sendConfirmation($o); // 800ms
$this->pdf->generateInvoice($o); // 1200ms
$this->analytics->track($o); // 300ms
// User blocked for 2.3s — all should be queued
}
// Dispatch heavy work to a queue — return immediately to the user
class OrderController {
public function store(Request $req): JsonResponse {
$order = Order::create($req->validated());
// Don't process payment synchronously — queue it
ProcessPayment::dispatch($order)->onQueue('payments');
GenerateInvoice::dispatch($order)->onQueue('documents');
SendConfirmationEmail::dispatch($order)->delay(now()->addSeconds(5));
return response()->json(['id' => $order->id], 202); // Accepted
}
}
// Worker processes jobs in the background
$ php artisan queue:work --queue=payments,documents,default