Laravel重试机制怎么配置

wen PHP项目 1

本文目录导读:

Laravel重试机制怎么配置

  1. 队列任务重试
  2. HTTP 请求重试
  3. 自定义重试逻辑
  4. 高级配置示例
  5. 数据库级别的重试
  6. 最佳实践建议

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, // 毫秒
        ],
    ],
],

最佳实践建议

  1. 指数退避策略:重试间隔逐渐增大,避免服务器压力
  2. 有限重试次数:设置合理上限(3-5 次)
  3. 重试幂等性:确保重试不会产生副作用
  4. 监控告警:记录重试和失败日志
  5. 区分错误类型:临时错误重试,永久错误直接失败

如果需要更复杂的重试策略,可以考虑使用专门的包如 spatie/laravel-queueable-actionspatie/backoff

抱歉,评论功能暂时关闭!