workerman 5.2.3 不内置消息队列,但适合作为稳定低开销的外部队列消费者;推荐 redis list(brpop阻塞消费)或 rabbitmq(支持ack/持久化),需多进程单连接、手动重试、幂等设计与异常防护。

Workerman 5.2.3 本身不带内置消息队列,但它极适合做**稳定、低开销、高可控的队列消费者**。关键不是“用 Workerman 做队列”,而是用它来**长期、并发、可靠地消费外部队列(如 Redis List 或 RabbitMQ)中的任务**。
选对队列存储:Redis List 最轻量实用
中小项目首选 Redis 的 List 结构,用 BRPOP 实现真阻塞消费,避免轮询空转:
- 生产端用
LPUSH queue:task {"id":123,"type":"send_email"} - 消费端每个 Worker 进程独占一个 Redis 连接,调用
$redis->brPop(['queue:task'], 1) - 超时设为 1 秒:既防长阻塞,又避免高频空查;返回 false 时安静等待下一轮
- 不要多个 Worker 共享一个 Redis 实例——会互相干扰 BRPOP 行为
多进程 + 每进程单连接:并发与隔离并重
Workerman 5.2.3 的 $worker->count 控制子进程数,每个子进程应独立初始化 Redis:
- 在
onWorkerStart回调里 new Redis() 并 connect,不能放全局或 onMessage 中 - 推荐设置
$worker->count = cpu_count() * 2(如 4 核机器设 8),兼顾 CPU 和 I/O - 业务出错时,用 try-catch 包裹处理逻辑,失败后记录日志,绝不 exit 或 throw 未捕获异常,否则进程退出,消费者少一个
失败重试与可靠性补丁要手动加
Workerman 不提供自动重试,需自己设计:
- 任务处理失败时,把原始数据用
LPUSH queue:task_failed存入失败队列,便于人工干预或定时重投 - 如需自动重试,可将失败任务
RPUSH queue:retry并加时间戳,另起一个定时器检查并重新投递 - 给任务加唯一 ID(如 UUID 或订单号),在消费前查 DB/Redis 判断是否已处理过,实现幂等
- 敏感操作(如扣库存、发短信)建议加数据库事务 + 消息状态标记,双重保险
进阶:对接 RabbitMQ 提升可靠性
若需消息持久化、ACK 确认、死信、限流等能力,换 RabbitMQ 更合适:
- 用
php-amqplib库,在onWorkerStart建立持久连接和 channel - 必须设
$channel->basic_qos(0, 1, false)(预取=1,no_ack=false) - 消费回调中拿到消息后立即处理,成功则
$channel->ack($delivery_info['delivery_tag']) - 捕获
AMQPConnectionClosedException,在onError里重建连接,防断连卡死











