CodeIgniter需手动集成Redis队列,推荐Predis客户端;任务须JSON序列化含class/method/args/attempts等字段;需自建CLI worker进程实现BLPOP消费、重试及错误兜底。

CodeIgniter 本身不内置 Redis 队列支持,要实现后台异步任务(比如发邮件、生成报表、批量推送),必须手动集成第三方客户端并设计轻量调度逻辑。直接用 CI_Redis 类或原生 Predis 都可以,但关键不在“连上 Redis”,而在“怎么把任务塞进去、谁来取、失败怎么兜住”。
怎么选 Redis 客户端:Predis 还是 phpredis 扩展?
优先用 Predis —— 它纯 PHP 实现,无需服务器装 phpredis 扩展,部署兼容性高,CI3 项目开箱即用。
-
Predis支持连接池、自动重连、管道(pipeline),适合任务队列场景 -
phpredis性能略高,但 CI3 默认不加载它,且connect()失败时容易静默挂掉,调试困难 - 别用社区版
CI_Redis(如 joelcox 版):它只封装了基础命令,没提供BLPOP/RPOPLPUSH等队列核心操作,也没任务重试或 ACK 机制
如何定义一个可执行的任务结构
Redis 队列本质是字符串列表(LPUSH / BLPOP),所以任务必须序列化成 JSON 字符串,包含必要字段:
-
class:完整命名空间类名,如"AppJobsSendEmailJob" -
method:要调用的方法名,如"handle" -
args:参数数组,所有值需可 JSON 序列化(不能传 resource、Closure) -
attempts:当前重试次数(初始为 0),用于幂等控制 -
max_attempts:最大允许重试次数(建议设 3) -
created_at:时间戳,便于监控积压
示例:{"class":"App\Jobs\SendEmailJob","method":"handle","args":[123],"attempts":0,"max_attempts":3,"created_at":1745066040}
如何启动一个常驻 worker 进程消费队列
CI 没有内置的 artisan queue:work,你得自己写一个 CLI 脚本,放在 application/cli/ 下(如 queue_worker.php),然后用 nohup php queue_worker.php & 启动:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 用
BLPOP queue:default 30阻塞读取,避免轮询浪费 CPU - 反序列化后,用
new $task['class']实例化,再call_user_func_array([$obj, $task['method']], $task['args'])执行 - 执行成功就
DEL临时 key;失败则INCRattempts 并RPUSH回队列(延迟重试需配合zset或额外 delay 队列) - 务必加
set_time_limit(0)和ignore_user_abort(TRUE),防止超时中断
注意:BLPOP 是单线程阻塞操作,一个进程只能消费一个队列;多队列需多个 worker 进程或改用 BRPOP 多 key 监听
为什么不能直接在控制器里 $this->redis->lpush('queue', $job) 就完事?
能 push,但只是“扔出去”——没人接、没失败重试、没日志、没监控、没并发控制。真实线上环境会遇到这些坑:
- worker 进程意外退出(OOM、信号中断),任务永久丢失,除非你用
RPOPLPUSH+ pending list 做可靠队列 - 任务执行中抛出未捕获异常,worker 直接崩,后续任务全卡住
- 多个 worker 同时 pop 同一任务(Redis 列表不是天然幂等),导致重复执行(比如重复扣款)
- 没有任务耗时统计,无法识别慢任务拖垮整个队列
真正可用的队列系统,至少得补上失败重试 + 死信队列 + 手动重放入口 —— 这些都得自己基于 Predis + CI 的钩子(如 post_system)补全,不是配个 redis.php 就算集成完了。

















