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

无框架PHP如何实现监听任务表并自动触发执行CURL任务

解决方案

核心方案:基于cron保底+任务锁+多进程调度实现

该方案完全可在现有PHP项目范围内落地,无需额外引入第三方服务,也不用调整现有API密钥的存储逻辑。

具体实现步骤

  • 第一步:优化任务表结构
    在原有任务表中新增字段:status(枚举值:pending待处理/processing处理中/success成功/failed失败)、retry_times(重试次数)、process_id(处理进程ID)、created_at(任务创建时间),用于实现任务状态管控和防重复消费。
  • 第二步:编写多进程消费脚本
    用PHP内置的pcntl_fork实现多进程消费,严格控制并发数,每个子进程仅处理一个任务,处理完成后直接退出,避免长期运行出现内存泄漏或进程异常:
    <?php
    // 消费脚本路径:/你的项目路径/consume_tasks.php
    
    // 1. 加全局锁,避免同时运行多个消费进程
    $lockFile = __DIR__ . '/task_consume.lock';
    $fp = fopen($lockFile, 'w');
    if (!flock($fp, LOCK_EX | LOCK_NB)) {
        // 已有消费进程在运行,直接退出
        exit(0);
    }
    
    // 引入现有项目的配置文件,直接复用API密钥、数据库连接等配置
    require_once __DIR__ . '/你的项目配置文件.php';
    
    // 最大并发数,根据第三方API的限流规则调整,建议先设为5
    $maxProcess = 5;
    $runningPids = [];
    
    // 2. 取待处理任务,加行锁避免重复消费
    $pdo->beginTransaction();
    $tasks = $pdo->query("SELECT * FROM 任务表名 WHERE status = 'pending' ORDER BY id ASC LIMIT {$maxProcess} FOR UPDATE")->fetchAll(PDO::FETCH_ASSOC);
    foreach ($tasks as $task) {
        $pdo->exec("UPDATE 任务表名 SET status = 'processing', process_id = ".getmypid()." WHERE id = ".$task['id']);
    }
    $pdo->commit();
    
    if (empty($tasks)) {
        // 没有待处理任务,直接释放锁退出
        flock($fp, LOCK_UN);
        fclose($fp);
        exit(0);
    }
    
    // 3.  fork子进程处理任务
    foreach ($tasks as $task) {
        $pid = pcntl_fork();
        if ($pid == -1) {
            die('进程创建失败');
        } elseif ($pid == 0) {
            // 子进程逻辑:处理单个任务
            try {
                // 直接复用你原有的curl调用逻辑
                你的原有任务处理函数($task);
                $pdo->exec("UPDATE 任务表名 SET status = 'success' WHERE id = ".$task['id']);
            } catch (\Exception $e) {
                $retryTimes = $task['retry_times'] + 1;
                // 最多重试3次,可自行调整
                $status = $retryTimes >= 3 ? 'failed' : 'pending';
                $pdo->exec("UPDATE 任务表名 SET status = '{$status}', retry_times = {$retryTimes} WHERE id = ".$task['id']);
            }
            exit(0); // 子进程处理完直接退出
        } else {
            $runningPids[$pid] = true;
        }
    }
    
    // 等待所有子进程执行完成
    while (count($runningPids) > 0) {
        $pid = pcntl_wait($status);
        unset($runningPids[$pid]);
    }
    
    // 释放锁
    flock($fp, LOCK_UN);
    fclose($fp);
    exit(0);
    
  • 第三步:配置双触发机制,实现任务实时执行
    不需要长期运行的监听进程,两个触发逻辑覆盖所有场景:
    1. 新增任务主动触发:在你插入任务表的代码后面,加一行触发消费的逻辑,只要有新任务写入就立刻启动消费,实现近似实时的执行效果:
    // 插入任务逻辑后加
    exec("nohup php /你的项目路径/consume_tasks.php > /dev/null 2>&1 &");
    
    1. cron保底触发:添加cron规则* * * * * php /你的项目路径/consume_tasks.php,每分钟执行一次消费脚本,避免主动触发失败、或失败重试的任务无人处理。
  • 第四步:可选优化
    • 给curl请求设置合理的超时时间,建议设为25秒,避免长时间卡住进程
    • 失败重试的任务可以加个重试间隔,避免连续请求故障接口浪费资源
    • 定期清理已完成的历史任务,避免任务表过大查询变慢

方案优势

  • 无单进程无限运行的问题,所有进程处理完任务就自动退出,就算出现异常也不需要手动重启,下一次触发会自动拉起新进程
  • 完全复用现有项目的所有配置,不需要修改API密钥的存储逻辑,改造成本极低
  • 并发可控,可根据第三方API的限流情况随时调整最大并发数,不会出现大量请求同时调用导致的超时错误
  • 任务按写入顺序执行,保证先进先出
  • 实时性足够,新增任务主动触发的延迟不超过1秒,和websocket触发的效果基本一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 18:57:03