Laravel调度任务触达API速率限制时可否暂停后继续执行
Laravel 批量API调用速率限制场景解决方案
两种实现方式均支持,更推荐第二种断点续跑的方案,稳定性更强。
方案1:当前任务直接暂停恢复
- 实现成本最低,适合对任务稳定性要求不高的场景
- 触发速率限制/处理完100个用户时,直接调用
sleep(3600)即可,1小时后进程会自动从断点继续执行后续逻辑 - 注意必须提前调整配置避免进程被强制终止:
- 队列worker启动时设置
--timeout=10800,保证超时时间大于2小时任务+1小时暂停的总时长 - 设置
--tries=1避免任务意外失败后重复执行,导致接口重复调用
- 队列worker启动时设置
- 缺点:如果队列进程意外退出、服务器重启,当前进度会完全丢失,需要从头开始执行同步
方案2:终止任务+断点续跑(生产环境推荐)
- 无需依赖长驻进程,异常场景下不会丢失进度,符合Laravel队列的最佳实践
- 实现逻辑如下:
- 任务中新增进度参数,标记当前已同步完成的用户偏移量
- 每次批量处理100个用户后,先记录当前进度到缓存
- 调度一个延迟1小时执行的同任务实例,传入下一批的偏移量参数
- 任务执行前先读取偏移量,从断点位置开始处理剩余用户
- 全部用户处理完成后清除对应缓存
- 代码示例:
<?php namespace App\Jobs; use App\Models\User; 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\Cache; use Illuminate\Support\Facades\Http; class SyncUsersToExternalPlatform implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected int $offset; public function __construct(int $offset = 0) { $this->offset = $offset; } public function handle() { // 从偏移量位置取100个待同步用户 $users = User::skip($this->offset)->take(100)->get(); if ($users->isEmpty()) { // 全部同步完成,清除进度缓存 Cache::forget('user_sync_offset'); return; } // 批量同步用户到第三方平台 foreach ($users as $user) { Http::post('https://external-platform.com/api/users', [ 'name' => $user->name, 'email' => $user->email, // 其他需要同步的字段 ]); } // 记录下一批次偏移量,缓存2小时避免过期 $nextOffset = $this->offset + 100; Cache::put('user_sync_offset', $nextOffset, 7200); // 延迟1小时调度下一批同步任务 self::dispatch($nextOffset)->delay(now()->addHour()); } }
- 额外优化点:可以保留原有的2小时调度器规则,每次调度前先判断缓存中是否存在未完成的同步进度,存在就跳过本次调度,避免重复任务。
内容的提问来源于stack exchange,提问作者Karna
相关产品推荐
相关产品推荐

