已正确安装think-queue并启用Redis驱动:需执行composer require topthink/think-queue,配置config/queue.php中default='redis'且connections.redis.type='redis',queue名一致,使用标准Job类而非闭包或字符串调用。

确认 think-queue 已正确安装并启用 Redis 驱动
没装 topthink/think-queue 或驱动没配对,后续所有命令都会报错或静默失败。TP6 默认不带队列组件,必须显式安装:
- 执行
composer require topthink/think-queue(注意不是think-queue单独包,官方已迁移到topthink/think-queue) - 配置文件位置必须是
config/queue.php(TP6.0+ 不再读extra/queue.php),否则php think queue:listen会 fallback 到sync驱动,任务看似“成功”实则同步执行 -
connections.redis.type必须为'redis'(小写),大小写错误会导致连接器初始化失败,日志里只显示Connection [redis] not found,不提示具体原因 - 确保
default值与connections.redis.queue一致,比如都设为'default',否则Queue::push()会发到不存在的队列名,监听时收不到任何消息
投递任务时必须用 Job 类,不能直接传闭包或字符串方法名
TP6 的 think-queue 不支持 Queue::push('App\Job\SendMail@handle', $data) 这类字符串调用,也不接受匿名函数——PHP 序列化闭包会失败,进程重启后无法反序列化。
- 必须定义标准 Job 类,实现
Illuminate\Contracts\Queue\ShouldQueue接口(或继承think\queue\Job) - Job 类中必须有
fire()方法(TP6 兼容旧版)或handle()方法(Laravel 风格),且参数只能是可序列化的数组、对象(需含__serialize)或基础类型 - 示例:
<?php namespace app\job; use think\queue\Job; class SendOrderEmail { public function fire(Job $job, $data) { // 发送邮件逻辑 \think\facade\Mail::send($data['to'], '订单通知', $data['content']); // 手动删除任务,否则会重试 $job->delete(); } } - 投递时用
Queue::push(new SendOrderEmail($payload)),不要用Queue::push('SendOrderEmail', $payload)
启动监听器前务必检查 Redis 连接和队列名是否匹配
php think queue:listen 启动后没反应、不消费、无报错,90% 是因为 Redis 连接参数或队列名不一致。Redis 本身不会报错,只是安静地往另一个 DB 或另一个 key 写数据。
- 检查
config/queue.php中connections.redis.host、port、password、select是否与config/cache.php里的 Redis 配置完全一致(尤其select,不同 DB 之间数据隔离) - 运行
redis-cli -h 127.0.0.1 -p 6379 -n 0 KEYS "queue:*"(把-n 0换成你实际的select值),看是否有queue:default这样的 key 存在;没有说明任务根本没发进去 - 监听命令要显式指定队列名:
php think queue:listen --queue=default,如果配置里queue是'robot',这里就得写--queue=robot,否则监听空队列 - 加
--verbose参数看实时日志:php think queue:listen --queue=default --verbose,能立刻看到“Popping job”还是“Nothing to process”
延迟任务和失败重试必须手动控制超时与重试次数
Redis 驱动默认不开启自动重试,retry_after 和 maxTries 都需要在配置或 Job 类里显式设置,否则失败任务会无限重试或立即丢弃。
立即学习“PHP免费学习笔记(深入)”;
- 在
config/queue.php的connections.redis下添加:'retry_after' => 60(单位秒,表示任务取出后 60 秒内未完成就放回队列) - Job 类中可覆盖重试次数:
public $tries = 3;
- 延迟投递用
Queue::later(300, new SendOrderEmail($data)),300 是秒数;注意:Redis List 不原生支持延迟,底层是用zset + scheduled模拟,所以必须确保connections.redis配置里有'delay' => 'redis'或使用 Stream(TP6.3+ 支持) - 失败任务默认进
failed驱动(若配置了failed.table),但 Redis 驱动不支持数据库 failed 表,得设为'type' => 'none',否则会抛出Driver [database] not supported
$job->delete() 就不会执行,而 retry_after 时间一到,任务又回到队列头部——如果这个异常是数据库连接失败或网络超时,下一次重试大概率还失败,最终卡死整个队列。必须在 fire() 内做兜底 try/catch,并根据错误类型决定是 $job->delete() 还是 $job->release(60)。



















