本文目录导读:

在 Laravel 中配置队列任务的重试次数和间隔,主要有以下几种方式:
在任务类中定义
通过属性定义
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SendEmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* 任务最大尝试次数
*
* @var int
*/
public $tries = 3;
/**
* 任务重试前延迟的秒数
*
* @var int
*/
public $backoff = 60; // Laravel 8.x 及以上
// 或者使用数组定义不同的延迟时间
// public $backoff = [10, 30, 60]; // 第1次重试延迟10秒,第2次延迟30秒,第3次延迟60秒
/**
* 执行任务
*
* @return void
*/
public function handle()
{
// 任务逻辑
}
}
Laravel 8.x 以下版本使用 retryAfter
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SendEmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* 任务最大尝试次数
*
* @var int
*/
public $tries = 3;
/**
* 任务重试前的延迟(秒) - Laravel 7.x 及以下
*
* @var int
*/
public $retryAfter = 60;
public function handle()
{
// 任务逻辑
}
}
在队列配置文件或运行时设置
通过 .env 文件配置
# 队列连接配置 QUEUE_CONNECTION=redis # 队列进程配置 (supervisor 配置中) QUEUE_WORKER_TRIES=3 QUEUE_WORKER_TIMEOUT=60 QUEUE_WORKER_SLEEP=3 QUEUE_WORKER_BACKOFF=30 QUEUE_WORKER_MAX_TIME=3600
运行时通过命令行参数
# 指定尝试次数 php artisan queue:work --tries=3 # 指定超时时间 php artisan queue:work --timeout=60 # 指定重试延迟 php artisan queue:work --backoff=30 # 组合使用 php artisan queue:work redis --tries=3 --timeout=60 --backoff=30
通过排队任务时动态设置
<?php
namespace App\Http\Controllers;
use App\Jobs\SendEmailJob;
use Illuminate\Http\Request;
class EmailController extends Controller
{
public function send()
{
// 创建任务时设置尝试次数和延迟
$job = new SendEmailJob();
// 动态设置尝试次数
$job->tries = 5;
// 动态设置重试延迟
$job->backoff = [30, 60, 120, 240, 480]; // 每次重试不同的延迟
// 推送到队列
dispatch($job);
}
}
使用队列事件监听器
<?php
namespace App\Providers;
use Illuminate\Queue\Events\JobFailed;
use Illuminate\Queue\Events\JobAttempted;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\ServiceProvider;
class QueueEventServiceProvider extends ServiceProvider
{
public function boot()
{
// 监听队列任务失败
Queue::failing(function (JobFailed $event) {
// $event->job->attempts() - 当前尝试次数
// $event->exception - 异常信息
logger('队列任务失败', [
'job' => $event->job->resolveName(),
'attempts' => $event->job->attempts(),
'error' => $event->exception->getMessage(),
]);
});
// 监听队列任务执行(包括重试)
Queue::after(function (JobAttempted $event) {
// 任务尝试后的回调
});
}
}
配置示例(Supervisor)
[program:worker] process_name=%(program_name)s_%(process_num)02d command=php /path/to/project/artisan queue:work redis --tries=3 --timeout=60 --backoff=30 autostart=true autorestart=true stopasgroup=true killasgroup=true user=www-data numprocs=8 redirect_stderr=true stdout_logfile=/path/to/project/storage/logs/worker.log stopwaitsecs=3600
完整示例:带指数退避的队列任务
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class ProcessPaymentJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** @var int 最大尝试次数 */
public $tries = 5;
/** @var array 重试间隔(秒)- 指数退避策略 */
public $backoff = [10, 30, 60, 180, 300];
/** @var int 超时时间(秒) */
public $timeout = 120;
/** @var bool 失败后是否删除任务 */
public $deleteWhenMissingModels = true;
public function handle()
{
try {
// 业务逻辑
$this->processPayment();
} catch (\Exception $e) {
Log::error('支付处理失败', [
'message' => $e->getMessage(),
'attempts' => $this->attempts(),
]);
// 如果还有重试次数,释放任务回去
if ($this->attempts() < $this->tries) {
$this->release($this->getNextBackoff());
} else {
throw $e; // 达到最大次数,抛出异常标记为永久失败
}
}
}
/**
* 获取下一次重试的延迟时间
*/
protected function getNextBackoff()
{
$attempts = $this->attempts();
if (is_array($this->backoff)) {
return $this->backoff[$attempts - 1] ?? $this->backoff[count($this->backoff) - 1];
}
return $this->backoff;
}
/**
* 任务最终失败的处理器
*/
public function failed(\Throwable $exception)
{
Log::error('支付处理最终失败', [
'error' => $exception->getMessage(),
]);
// 可以在这里发送通知
}
}
优雅处理重试的方法
<?php
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class HandleExternalApi implements ShouldQueue
{
use Dispatchable;
public $tries = 3;
public $backoff = [15, 60, 300];
public $timeout = 120;
public function handle()
{
$response = $this->callExternalApi();
if ($response->status() === 429) {
// 速率限制,释放任务并延迟重试
$this->release(300);
}
if ($response->status() !== 200) {
throw new \Exception('外部API错误');
}
// 处理成功
}
}
注意事项
- 重试次数配置位置优先级:任务属性 > 队列命令参数 > 队列配置
backoff属性:Laravel 8.x 及以上使用,替代了旧的retryAfter- 防止无限重试:确保
tries不会设置为很大的值 - 错误日志:记录每次重试的原因和时间
- 监控:使用 Laravel Horizon 或自定义监控来跟踪队列状态
这样配置后,Laravel 会自动处理队列任务的重试机制,当任务执行失败时会按照配置的时间和次数自动重试。