无框架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); - 第三步:配置双触发机制,实现任务实时执行
不需要长期运行的监听进程,两个触发逻辑覆盖所有场景:- 新增任务主动触发:在你插入任务表的代码后面,加一行触发消费的逻辑,只要有新任务写入就立刻启动消费,实现近似实时的执行效果:
// 插入任务逻辑后加 exec("nohup php /你的项目路径/consume_tasks.php > /dev/null 2>&1 &");- cron保底触发:添加cron规则
* * * * * php /你的项目路径/consume_tasks.php,每分钟执行一次消费脚本,避免主动触发失败、或失败重试的任务无人处理。
- 第四步:可选优化
- 给curl请求设置合理的超时时间,建议设为25秒,避免长时间卡住进程
- 失败重试的任务可以加个重试间隔,避免连续请求故障接口浪费资源
- 定期清理已完成的历史任务,避免任务表过大查询变慢
方案优势
- 无单进程无限运行的问题,所有进程处理完任务就自动退出,就算出现异常也不需要手动重启,下一次触发会自动拉起新进程
- 完全复用现有项目的所有配置,不需要修改API密钥的存储逻辑,改造成本极低
- 并发可控,可根据第三方API的限流情况随时调整最大并发数,不会出现大量请求同时调用导致的超时错误
- 任务按写入顺序执行,保证先进先出
- 实时性足够,新增任务主动触发的延迟不超过1秒,和websocket触发的效果基本一致
内容的提问来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

