queueType) ); // Create dead letter job entry $deadLetterJob = DeadLetterJob::fromFailedJob( failedJob: $failedJob, deadLetterQueueName: $dlqName, failureReason: $failureReason ); // Add to dead letter queue $this->deadLetterQueue->addFailedJob($deadLetterJob); // Remove from original job index $this->persistenceLayer->deleteJob($failedJob->jobId); } /** * Move a job to dead letter queue when max attempts are exceeded */ public function handleJobFailure( string $jobId, \Throwable $exception, int $maxAttempts = 3 ): bool { $jobEntry = $this->persistenceLayer->getJobById($jobId); if (! $jobEntry) { return false; } // Check if max attempts exceeded if ($jobEntry->attempts >= $maxAttempts) { $failureReason = FailureReason::fromException($exception); $this->moveJobToDeadLetterQueue( failedJob: $jobEntry, failureReason: $failureReason ); return true; } return false; } /** * Retry a job from dead letter queue */ public function retryJob(string $deadLetterJobId): bool { return $this->deadLetterQueue->retryJob($deadLetterJobId); } /** * Get failed jobs for monitoring/admin interface */ public function getFailedJobs( ?QueueName $originalQueue = null, int $limit = 100 ): array { if ($originalQueue) { return $this->deadLetterQueue->getJobsByOriginalQueue($originalQueue, $limit); } // Get jobs from all dead letter queues $allJobs = []; $queues = $this->deadLetterQueue->getAvailableQueues(); foreach ($queues as $queueName) { $jobs = $this->deadLetterQueue->getJobs($queueName, $limit); $allJobs = array_merge($allJobs, $jobs); } // Sort by moved_to_dlq_at descending usort($allJobs, fn ($a, $b) => strcmp($b->movedToDlqAt, $a->movedToDlqAt)); return array_slice($allJobs, 0, $limit); } /** * Get dead letter queue statistics */ public function getStatistics(): array { $queues = $this->deadLetterQueue->getAvailableQueues(); $stats = []; foreach ($queues as $queueName) { $stats[$queueName->toString()] = $this->deadLetterQueue->getQueueStats($queueName); } return $stats; } /** * Clear all jobs from a dead letter queue */ public function clearDeadLetterQueue(DeadLetterQueueName $queueName): int { return $this->deadLetterQueue->clearQueue($queueName); } /** * Retry all jobs in a dead letter queue */ public function retryAllJobs(DeadLetterQueueName $queueName): int { return $this->deadLetterQueue->retryAllJobs($queueName); } /** * Delete a specific job from dead letter queue */ public function deleteJob(string $deadLetterJobId): bool { return $this->deadLetterQueue->deleteJob($deadLetterJobId); } /** * Get all available dead letter queues */ public function getAvailableQueues(): array { return $this->deadLetterQueue->getAvailableQueues(); } }