You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel队列中合并FetchKeywordStatistics作业以减少第三方API请求是否可行?

Laravel队列合并关键词请求实现方案

完全可行,通过临时存储收集关键词+聚合作业批量处理的方式,就能实现合并多个客户端请求的关键词,大幅减少对第三方API的调用次数,同时适配对方的限流和批量限制。

核心思路

  • 不再直接分发单个关键词处理作业,而是将所有待查询的关键词存入临时存储(如Redis)
  • 调度一个聚合作业,延迟一段时间执行,用来收集这段时间内的所有关键词
  • 聚合作业执行时,取出所有关键词,去重、分批后调用第三方API,再处理结果返回给客户端

具体实现步骤

1. 修改API控制器逻辑:收集关键词并调度聚合作业

控制器不再直接分发原有的FetchKeywordStatistics作业,而是将关键词存入Redis集合(自动去重),并确保只有一个聚合作业在调度中:

use Illuminate\Support\Facades\Redis;
use App\Jobs\AggregateKeywordStatistics;

public function fetchStats(Request $request)
{
    // 获取客户端传入的关键词数组
    $keywords = $request->validate([
        'keywords' => 'required|array|min:1'
    ])['keywords'];

    // 将关键词存入Redis集合(自动去重)
    Redis::sadd('pending_keywords', ...$keywords);

    // 加锁避免重复调度聚合作业
    if (!Redis::exists('aggregate_job_lock')) {
        // 锁定1分钟,防止重复触发
        Redis::setex('aggregate_job_lock', 60, 'active');
        // 延迟5秒执行,给时间收集更多请求
        AggregateKeywordStatistics::dispatch()->delay(now()->addSeconds(5));
    }

    // 返回查询标识,供客户端后续获取结果
    return response()->json([
        'query_id' => uniqid(),
        'message' => '请求已受理,稍后可通过query_id查询结果'
    ]);
}

2. 创建聚合作业:批量处理关键词

新建AggregateKeywordStatistics作业,负责取出所有待处理关键词,分批调用第三方API,并处理结果:

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\Redis;
use Illuminate\Support\Facades\Http;

class AggregateKeywordStatistics implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function handle()
    {
        try {
            // 取出所有待处理关键词并清空集合
            $keywords = Redis::smembers('pending_keywords');
            Redis::del('pending_keywords');

            if (empty($keywords)) {
                return;
            }

            // 按第三方限制的100个关键词分批
            $keywordBatches = array_chunk($keywords, 100);

            foreach ($keywordBatches as $batch) {
                // 遵守第三方限流:每分钟最多3次请求
                $this->enforceThirdPartyRateLimit();

                // 调用第三方API获取统计数据
                $response = Http::get('https://third-party-api.com/stats', [
                    'keywords' => implode(',', $batch)
                ]);
                $response->throw(); // 处理请求失败的情况
                $statsData = $response->json();

                // 将结果存入缓存,供客户端查询
                foreach ($batch as $keyword) {
                    Redis::setex(
                        "keyword_stats:{$keyword}",
                        3600, // 缓存1小时
                        json_encode($statsData[$keyword] ?? [])
                    );
                }
            }
        } catch (\Exception $e) {
            // 请求失败时,将关键词放回集合,重新调度作业
            if (!empty($keywords)) {
                Redis::sadd('pending_keywords', ...$keywords);
            }
            // 延迟10秒重试
            self::dispatch()->delay(now()->addSeconds(10));
            throw $e; // 让队列记录错误日志
        } finally {
            // 释放锁,允许下次调度聚合作业
            Redis::del('aggregate_job_lock');
        }
    }

    /**
     * 实现第三方API的限流控制
     */
    protected function enforceThirdPartyRateLimit()
    {
        $throttleKey = 'third_party_api_requests';
        $requestCount = Redis::incr($throttleKey);

        // 第一次请求时设置过期时间(1分钟)
        if ($requestCount === 1) {
            Redis::expire($throttleKey, 60);
        }

        // 超过每分钟3次限制时,等待到下一分钟
        if ($requestCount > 3) {
            $remainingSeconds = Redis::ttl($throttleKey);
            sleep($remainingSeconds + 1);
            // 重置计数
            Redis::set($throttleKey, 1);
            Redis::expire($throttleKey, 60);
        }
    }
}

3. 新增结果查询接口

客户端通过之前拿到的query_id(或直接按关键词)查询统计结果:

public function getStatsResult(Request $request)
{
    $keyword = $request->input('keyword');
    $stats = Redis::get("keyword_stats:{$keyword}");

    if (!$stats) {
        return response()->json([
            'status' => 'pending',
            'message' => '统计结果尚未生成,请稍后重试'
        ], 202);
    }

    return response()->json([
        'status' => 'completed',
        'keyword' => $keyword,
        'stats' => json_decode($stats, true)
    ]);
}

关键注意事项

  • 关键词去重:用Redis集合存储关键词,自动避免重复查询同一个关键词,减少无效请求
  • 延迟调度:延迟几秒执行聚合作业,能最大化合并更多客户端的请求,进一步减少第三方API调用次数
  • 锁机制:防止多个聚合作业同时执行,避免重复请求第三方API
  • 错误重试:请求第三方API失败时,将关键词放回集合并重试,确保数据不丢失
  • 限流控制:严格遵守第三方的每分钟3次请求限制,避免被封禁

内容的提问来源于stack exchange,提问作者Niels Mouthaan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:20:26