本文目录导读:

Laravel 的重试机制主要涉及队列任务重试和HTTP 请求重试两个核心场景,下面分别介绍配置方法。
队列任务重试
1 配置最大尝试次数
在 config/queue.php 中配置全局重试次数:
// config/queue.php
'connections' => [
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90, // 任务超时时间(秒)
'max_attempts' => 3, // 最大重试次数
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'retry_after' => 90,
'block_for' => null,
'max_attempts' => 3,
],
],
2 任务级别配置(推荐)
在任务类中定义 $tries 属性:
class ProcessPodcast implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 3; // 最大重试次数
public function handle()
{
// 任务逻辑
}
}
3 配置重试延迟
在任务类中定义 backoff 方法:
class ProcessPodcast implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 3;
/**
* 重试延迟时间(秒)
*/
public function backoff()
{
return [2, 5, 10]; // 第1次重试等待2秒,第2次5秒,第3次10秒
}
}
或者使用常量方式:
class ProcessPodcast implements ShouldQueue
{
public $backoff = 5; // 每次重试等待5秒
}
HTTP 请求重试
1 使用 Laravel HTTP 客户端
use Illuminate\Support\Facades\Http;
$response = Http::retry(3, 100, function ($exception) {
// 仅在特定条件下重试
return $exception instanceof ConnectionException;
})->post('https://api.example.com/users');
参数说明:
- 第一个参数:重试次数
- 第二个参数:重试间隔(毫秒)
- 第三个参数:可选的回调,决定是否重试
2 设置重试延迟策略
$response = Http::retry(3, function ($attempt) {
// 指数退避策略:第1次100ms,第2次200ms,第3次400ms
return 100 * pow(2, $attempt - 1);
})->get('https://api.example.com');
自定义重试逻辑
1 在任务中手动重试
class ProcessPodcast implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 5;
public function handle()
{
try {
// 任务逻辑
if (someCondition()) {
throw new \Exception('处理失败');
}
} catch (\Exception $e) {
// 释放任务回队列进行重试
if ($this->attempts() < $this->tries) {
$this->release(30); // 30秒后重试
return;
}
// 达到最大重试次数,标记为失败
$this->fail($e);
}
}
}
2 自定义失败处理
创建 App\Exceptions\Handler 中的 failed 方法:
// app/Exceptions/Handler.php
protected function failed(Throwable $exception, $failedJob)
{
// 记录失败日志
Log::error('Job failed: ' . $failedJob->payload(), [
'exception' => $exception
]);
// 发送通知
Notification::route('mail', 'admin@example.com')
->notify(new JobFailedNotification($failedJob, $exception));
}
高级配置示例
1 唯一任务(避免重复执行)
class ProcessPodcast implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, ShouldBeUnique;
public $uniqueFor = 3600; // 1小时内唯一
public $tries = 3;
public $maxExceptions = 2; // 最多异常次数
public function handle()
{
// 处理逻辑
}
}
2 配置队列工作器
命令行启动工作器时指定参数:
# 运行队列工作器,最多尝试3次 php artisan queue:work --tries=3 # 指定队列 php artisan queue:work --queue=high,default --tries=3 # 设置超时时间 php artisan queue:work --timeout=60 --tries=3 # 设置睡眠时间(无任务时) php artisan queue:work --sleep=3 --tries=3
3 自定义重试中间件
namespace App\Queue\Middleware;
class RetryMiddleware
{
public function handle($job, $next)
{
try {
return $next($job);
} catch (\Exception $e) {
// 自定义重试逻辑
if ($job->attempts() > 5) {
throw $e;
}
// 根据异常类型决定延迟
$delay = $e instanceof RateLimitException ? 60 : 10;
$job->release($delay);
}
}
}
在任务中使用:
class ProcessPodcast implements ShouldQueue
{
public function middleware()
{
return [new RetryMiddleware];
}
}
数据库级别的重试
1 配置数据库重试
// config/database.php
'mysql' => [
'driver' => 'mysql',
// ... 其他配置
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => true,
],
'read' => [
'retry' => [
'attempts' => 3,
'delay' => 100, // 毫秒
],
],
],
最佳实践建议
- 指数退避策略:重试间隔逐渐增大,避免服务器压力
- 有限重试次数:设置合理上限(3-5 次)
- 重试幂等性:确保重试不会产生副作用
- 监控告警:记录重试和失败日志
- 区分错误类型:临时错误重试,永久错误直接失败
如果需要更复杂的重试策略,可以考虑使用专门的包如 spatie/laravel-queueable-action 或 spatie/backoff。