Job Replay
Job Replay
Job replay allows you to re-dispatch failed or completed jobs using their stored payloads.
Requirements
Job replay requires payload storage to be enabled:
// config/queue-monitor.php
'storage' => [
'store_payload' => true,
],
Important: Payloads are stored as-is, including all job properties and data. Ensure your payload size doesn't exceed the configured limit (default: 64KB).
How It Works
- When a job is queued, the package stores its complete serialized payload
- On replay, the payload is extracted and re-dispatched to the original queue
- A new job monitor record is created with a link to the original job
Replaying Jobs
Via Facade
use Cbox\LaravelQueueMonitor\Facades\LaravelQueueMonitor as QueueMonitor;
$replayData = QueueMonitor::replay('9a123456-7890-1234-5678-90abcdef1234');
echo "Replayed to queue: {$replayData->queue}\n";
echo "New job ID: {$replayData->newJobId}\n";
Via Artisan Command
php artisan queue-monitor:replay 9a123456-7890-1234-5678-90abcdef1234
Via REST API
curl -X POST http://localhost/api/queue-monitor/jobs/{uuid}/replay
Replay Validation
The package performs several validation checks before replaying:
- Job exists: The UUID must correspond to an existing job record
- Payload stored: The job must have a stored payload
- Job class exists: The job class must still be available in your codebase
- Not processing: Cannot replay jobs currently being processed
- Queue exists: The target queue and connection must exist
Retry Chain
When a job is replayed, it maintains a link to the original:
$original = QueueMonitor::getJob($originalUuid);
$retries = QueueMonitor::getRetryChain($originalUuid);
foreach ($retries as $attempt) {
echo "Attempt {$attempt->attempt}: {$attempt->status->label()}\n";
if ($attempt->retried_from_id) {
echo " Retried from: {$attempt->retriedFrom->uuid}\n";
}
}
Use Cases
Failed Job Recovery
use Cbox\LaravelQueueMonitor\Enums\JobStatus;
$failedJobs = JobMonitor::withStatus(JobStatus::FAILED)
->whereDate('completed_at', today())
->get();
foreach ($failedJobs as $job) {
try {
QueueMonitor::replay($job->uuid);
Log::info("Replayed failed job: {$job->uuid}");
} catch (\Exception $e) {
Log::error("Failed to replay {$job->uuid}: {$e->getMessage()}");
}
}
Development/Testing
Replay production jobs in development:
// On production
$job = QueueMonitor::getJob($uuid);
$payload = $job->payload;
// Copy payload to development database, then replay
QueueMonitor::replay($uuid);
Bulk Replay
Replay multiple jobs with specific criteria:
$filters = new JobFilterData(
statuses: [JobStatus::FAILED],
jobClasses: ['App\\Jobs\\SendEmail'],
completedAfter: Carbon::now()->subHours(1),
);
$jobs = QueueMonitor::getJobs($filters);
foreach ($jobs as $job) {
QueueMonitor::replay($job->uuid);
}
Limitations
- State Dependencies: If a job depends on external state (database records, files, etc.), ensure that state still exists before replaying
- Idempotency: Jobs should be idempotent to safely replay without side effects
- Payload Size: Large payloads may hit storage limits
- Class Availability: The job class must exist in your current codebase
Events
Job replay triggers events you can listen for:
use Cbox\LaravelQueueMonitor\Events\JobReplayRequested;
Event::listen(JobReplayRequested::class, function ($event) {
Log::info("Job replayed: {$event->originalJob->uuid}");
Log::info("New job ID: {$event->replayData->newJobId}");
});
Best Practices
- Enable in Development: Always enable payload storage in development and testing
- Disable in Production: Consider disabling if payload storage is a concern
- Prune Regularly: Remove old payloads to manage storage
- Monitor Replay Success: Track replay success rates
- Add Replay Logic to Jobs: Make jobs replay-safe with idempotency checks