Laravel retryUntil 作业在第 4 次重试没有失败后退出
Laravel retryUntil job exits after 4th retry without failing
我正在尝试调试我的 PHP 应用程序的一些奇怪行为。它是 运行 Laravel 6 + AWS SQS。该程序使用作业从 VoIP 提供商的 API 下载通话录音。 API 有 10req/minute 的严格速率限制,所以我正在限制我这边的请求。该作业配置为尝试使用 retryUntil
方法在 24 小时内完成。但是,该作业在尝试 4 次后从队列中消失。它不会失败。作业的 failed
方法永远不会执行(我已经将日志记录和 Sentry::capture 放在那里)。它不在 failed_jobs table 上。最后一条日志显示“无法完成作业,将在 ... 秒后重试”,它就在 release
调用之前。但是,作业只是从队列中消失,再也不会执行。
我正在记录尝试次数、最大尝试次数、超时时间等。一切似乎都已正确配置。这是我的代码的(本质):
public function handle()
{
/** @var Track $track */
$track = Track::idOrUuId($this->trackId);
$this->logger->info('Downloading track', [
'trackId' => $track->getId(),
'attempt' => $this->attempts(),
'retryUntil' => $this->job->timeoutAt(),
'maxTries' => $this->job->maxTries(),
]);
$throttleKey = sprintf('track.download.%s', $track->getUser()->getTeamId());
if (!$this->rateLimiter->tooManyAttempts($throttleKey, self::MAX_ALLOWED_JOBS)) {
$this->downloadTrack($track);
$this->rateLimiter->hit($throttleKey, 60);
} else {
$delay = random_int(10, 100) + $this->rateLimiter->availableIn($throttleKey);
$this->logger->info('Throttling track download.', [
'trackId' => $track->getId(),
'delay' => $delay,
]);
$this->release($delay);
}
}
public function retryUntil(): DateTimeInterface
{
return now()->addHours(24);
}
public function failed(Exception $exception)
{
$this->logger->info('Job failed', ['exception' => $exception->getMessage()];
Sentry::captureException($exception);
}
我发现了问题,并将其发布在这里,以供将来可能遇到困难的任何人使用。这一切都归结为一个简单的配置。在 AWS SQS 中,我正在使用的队列配置了 DLQ
(Dead-Letter 队列)并且 Maximum receives
设置为 4。根据 SQS 文档
The Maximum receives value determines when a message will be sent to the DLQ. If the ReceiveCount for a message exceeds the maximum receive count for the queue, Amazon SQS moves the message to the associated DLQ (with its original message ID).
由于这是一个基础配置,它会覆盖您可能传递给作业的任何 Laravel 参数。并且因为消息只是简单地从队列中移除,处理作业实际上并没有失败,所以failed
方法没有被执行。
我正在尝试调试我的 PHP 应用程序的一些奇怪行为。它是 运行 Laravel 6 + AWS SQS。该程序使用作业从 VoIP 提供商的 API 下载通话录音。 API 有 10req/minute 的严格速率限制,所以我正在限制我这边的请求。该作业配置为尝试使用 retryUntil
方法在 24 小时内完成。但是,该作业在尝试 4 次后从队列中消失。它不会失败。作业的 failed
方法永远不会执行(我已经将日志记录和 Sentry::capture 放在那里)。它不在 failed_jobs table 上。最后一条日志显示“无法完成作业,将在 ... 秒后重试”,它就在 release
调用之前。但是,作业只是从队列中消失,再也不会执行。
我正在记录尝试次数、最大尝试次数、超时时间等。一切似乎都已正确配置。这是我的代码的(本质):
public function handle()
{
/** @var Track $track */
$track = Track::idOrUuId($this->trackId);
$this->logger->info('Downloading track', [
'trackId' => $track->getId(),
'attempt' => $this->attempts(),
'retryUntil' => $this->job->timeoutAt(),
'maxTries' => $this->job->maxTries(),
]);
$throttleKey = sprintf('track.download.%s', $track->getUser()->getTeamId());
if (!$this->rateLimiter->tooManyAttempts($throttleKey, self::MAX_ALLOWED_JOBS)) {
$this->downloadTrack($track);
$this->rateLimiter->hit($throttleKey, 60);
} else {
$delay = random_int(10, 100) + $this->rateLimiter->availableIn($throttleKey);
$this->logger->info('Throttling track download.', [
'trackId' => $track->getId(),
'delay' => $delay,
]);
$this->release($delay);
}
}
public function retryUntil(): DateTimeInterface
{
return now()->addHours(24);
}
public function failed(Exception $exception)
{
$this->logger->info('Job failed', ['exception' => $exception->getMessage()];
Sentry::captureException($exception);
}
我发现了问题,并将其发布在这里,以供将来可能遇到困难的任何人使用。这一切都归结为一个简单的配置。在 AWS SQS 中,我正在使用的队列配置了 DLQ
(Dead-Letter 队列)并且 Maximum receives
设置为 4。根据 SQS 文档
The Maximum receives value determines when a message will be sent to the DLQ. If the ReceiveCount for a message exceeds the maximum receive count for the queue, Amazon SQS moves the message to the associated DLQ (with its original message ID).
由于这是一个基础配置,它会覆盖您可能传递给作业的任何 Laravel 参数。并且因为消息只是简单地从队列中移除,处理作业实际上并没有失败,所以failed
方法没有被执行。