laravel-queue
Auto-invoked skill
Create jobs, events, listeners with rate limiting
Trigger Keywords
This skill automatically activates when Claude detects these keywords:
queue
job
event
listener
horizon
dispatch
Overview
The laravel-queue skill provides expertise for background job processing. It covers job creation, event-driven architecture, rate limiting, retries, and monitoring with Horizon.
What This Skill Provides
- Job Creation - Queueable jobs with proper patterns
- Event/Listener - Event-driven architecture
- Rate Limiting - Throttle job processing
- Retry Logic - Backoff, max attempts, failure handling
- Batching - Process related jobs together
- Horizon - Queue monitoring and configuration
Example Conversations
# Creating a job
"Create a job to process large CSV imports in chunks"
# Event-driven
"Set up events for when a user places an order"
# Rate limiting
"Limit my email sending job to 100 per minute"
# Failure handling
"What happens when a job fails? How do I handle it?"
Job Example
<?php
namespace App\Jobs;
use App\Models\Order;
use App\Services\PaymentGateway;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\Middleware\RateLimited;
use Illuminate\Queue\Middleware\WithoutOverlapping;
class ProcessPayment implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 3;
public int $backoff = 60; // seconds
public int $timeout = 120;
public function __construct(
public Order $order
) {}
public function middleware(): array
{
return [
new RateLimited('payments'),
new WithoutOverlapping($this->order->id),
];
}
public function handle(PaymentGateway $gateway): void
{
$result = $gateway->charge($this->order);
if ($result->failed()) {
$this->fail($result->error());
}
}
public function failed(\Throwable $exception): void
{
// Notify admin, log, etc.
}
}
Dispatching Jobs
// Dispatch immediately to queue
ProcessPayment::dispatch($order);
// Dispatch with delay
ProcessPayment::dispatch($order)->delay(now()->addMinutes(10));
// Dispatch to specific queue
ProcessPayment::dispatch($order)->onQueue('payments');
// Dispatch after response sent
ProcessPayment::dispatchAfterResponse($order);
// Conditional dispatch
ProcessPayment::dispatchIf($order->isPending(), $order);
// Chain jobs
Bus::chain([
new ProcessPayment($order),
new SendReceipt($order),
new UpdateInventory($order),
])->dispatch();
Rate Limiting
// In AppServiceProvider
RateLimiter::for('payments', function (object $job) {
return Limit::perMinute(100);
});
// Per-user rate limiting
RateLimiter::for('emails', function (object $job) {
return Limit::perMinute(10)->by($job->user->id);
});
Unique Jobs
use Illuminate\Contracts\Queue\ShouldBeUnique;
class ProcessWebhook implements ShouldQueue, ShouldBeUnique
{
public int $uniqueFor = 3600; // seconds
public function uniqueId(): string
{
return $this->webhook->id;
}
}
Common Pitfalls
// 1. Not Serializing Properly - Models must use SerializesModels
// Bad - serializes entire model data
public function __construct(public array $orderData) {}
// Good - only serializes model ID
use SerializesModels;
public function __construct(public Order $order) {}
// 2. Missing Failed Job Handler
public function failed(\Throwable $e): void
{
Log::error('Job failed', [
'order_id' => $this->order->id,
'error' => $e->getMessage(),
]);
}
// 3. Not Setting Appropriate Timeouts
public int $timeout = 30; // seconds
public bool $failOnTimeout = true;
// 4. Infinite Retry Loops
public int $tries = 3;
public array $backoff = [10, 60, 300]; // 10s, 1m, 5m
// 5. Heavy Data in Queued Jobs
// Bad - stores large data
ProcessCsv::dispatch($csvContent);
// Good - store file path
ProcessCsv::dispatch($filePath);
// 6. Not Restarting Workers After Deploy
// php artisan queue:restart
Package Integration
- laravel/horizon - Redis queue monitoring dashboard
- spatie/laravel-failed-job-monitor - Failed job notifications
- spatie/laravel-schedule-monitor - Schedule monitoring
Best Practices
- Use specific queues for different priorities
- Set appropriate timeouts and retry limits
- Handle failures gracefully
- Monitor queue length and worker health
- Use Horizon for Redis queue monitoring
- Serialize only what's needed
- Use unique jobs to prevent duplicates
- Test job dispatch and handling
Testing Jobs
use Illuminate\Support\Facades\Queue;
it('dispatches payment job on order', function () {
Queue::fake();
$order = Order::factory()->create();
$order->process();
Queue::assertPushed(ProcessPayment::class, function ($job) use ($order) {
return $job->order->id === $order->id;
});
});
// Test job execution
it('charges the order', function () {
$order = Order::factory()->create();
(new ProcessPayment($order))->handle(app(PaymentGateway::class));
expect($order->fresh()->status)->toBe('paid');
});
Related Commands
- /laravel-agent:job:make - Create queued jobs