CodeIgniter原生不支持Laravel风格队列调度,CI3需通过CLI控制器配合crontab实现定时任务,CI4须用spark命令且满足类名、继承、配置三条件;环境路径、日志重定向和数据库伪队列是关键。

CodeIgniter 原生不支持 Laravel 风格的队列调度(如 queue:work 或 dispatch()),也没有内置的长期运行消费者进程;它的定时任务必须走「CLI + Cron」组合,且 CI3 与 CI4 的实现机制完全不同——混用会导致命令找不到、服务未加载、数据库连不上。
CI3 怎么写一个能被 crontab 调用的控制器方法
CI3 没有命令行注册机制,靠 index.php 直接路由到控制器方法。关键不是“能不能写”,而是“怎么写才不会在 crontab 里静默失败”:
- 控制器构造函数里必须加
if (!$this->input->is_cli_request()) { show_error('CLI only'); },否则通过浏览器或 curl 触发时会报错或执行异常 - 参数不能依赖
$_GET或$argv,要用$this->uri->segment(3)(第3段是第一个参数)、segment(4)等获取,例如clean_temp_files 7中的7 - 所有模型、库、助手必须在构造函数中显式
$this->load->xxx(),CLI 下自动加载规则不生效 - 日志必须用
log_message(),别用echo或print_r,否则 crontab 重定向后看不到输出
示例调用命令:/usr/bin/php /var/www/myapp/index.php cron daily_backup
CI4 的 spark 命令为什么总显示“command not found”
CI4 强制要求 CLI 逻辑封装为 app/Commands/xxxCommand.php,且必须满足三个硬性条件,缺一不可:
- 类名必须以
Command结尾(如SendEmailCommand),否则spark list不识别 - 必须继承
CodeIgniter\Commands\BaseCommand,并在构造函数中设置$this->group和$this->description,否则spark认为它不是合法命令 - 参数必须用
$this->getArgument('name')或$this->getOption('force')获取,直接读$argv会跳过参数解析,导致值为空
常见错误:把 CI3 风格的控制器复制进 app/Commands/,没改继承关系、没设 group、没重命名类——spark 就当它不存在。
crontab 执行失败的 90% 原因是环境变量和路径不对
你在终端手动跑通了 php index.php cron daily_backup,不代表 crontab 能跑通。crontab 使用极简 shell 环境,PATH、当前目录、PHP 可执行路径都和你登录用户不同:
- 绝对路径必须写全:
/usr/bin/php(查路径用which php),不能只写php - 入口文件路径必须绝对:
/var/www/myapp/public/index.php,不能写相对路径或软链接路径 - 建议在 crontab 行首加
cd /var/www/myapp &&,避免因工作目录错误导致文件加载失败 - 务必重定向日志:
> /var/log/ci-cron-daily.log 2>&1,否则失败时完全无迹可寻
典型 crontab 条目:0 2 * * * cd /var/www/myapp && /usr/bin/php public/index.php cron daily_backup >> /var/log/ci-daily.log 2>&1
想用 Redis 队列或后台常驻进程?得自己补
CI 原生不提供 queue:work、不监听 Redis、不管理进程生命周期。如果真需要异步/高并发任务,只能外挂:
- 用
exec()启动独立 PHP 进程(如php worker.php &),但要自己处理僵尸进程、信号捕获、PID 文件锁、重启逻辑 - 引入第三方包如
codeigniter4/tasks(Composer 安装),它模拟 Laravel Scheduler,但底层仍是每分钟 Cron 触发一次spark tasks:run,不是长连接消费者 - 数据库伪队列是 CI3 最稳妥的方案:建
jobs表,状态字段 +locked_at+WHERE status = 'pending' AND locked_at IS NULL LIMIT 1查询,配合每分钟 Cron 轮询——简单、可控、无额外依赖
真正容易被忽略的是:CI 的「定时任务」本质是「定期检查有没有事干」,不是「有个活儿就立刻推给工人」;所有想绕过 Cron 走纯事件驱动的尝试,都会卡在进程管理这一关。


















