horizon需手动配置路由、队列名和redis清理,否则监控失真;不支持redis集群,waiting统计滞后,且“成功”仅指执行完成而非业务成功。

Horizon 本身不自动暴露监控页面,也不默认捕获所有队列异常;它只反映“是否执行完”,不判断“是否成功”。要真正用起来,得手动配路由、对齐队列名、清理 Redis 堆积数据,否则看到的 waiting 数和实际积压可能严重脱节。
Horizon Web 页面打不开:/horizon 路由没注册或权限失控
装完 laravel/horizon 并运行 php artisan horizon,不代表你能访问 /horizon。它只是起了 worker 进程,Web 控制台是另一套逻辑。
- 必须在
routes/web.php中显式添加Horizon::routes();—— 不是自动加载,也不是靠中间件隐式启用 - 强烈建议包在环境判断里:
if (app()->environment('local', 'staging')) { Horizon::routes(); },生产环境直接禁用,避免敏感指标泄露 - 如果你项目全局加了
auth中间件(比如强制登录),Horizon::routes()默认不带任何认证,得手动指定:Horizon::routes()->middleware(['auth']); - 确认 Nginx/Apache 没把
/horizon路径重写或拦截掉;常见错误是伪静态规则把所有非文件请求都转给了index.php,但漏掉了这个前缀
任务一直卡在 “waiting”:队列名不匹配 or Supervisor 没真跑起来
Horizon 的 UI 显示 waiting=50,但你发的任务就是不消费——大概率不是 Horizon 坏了,而是底层没对齐。
- Horizon 默认只监听
default队列;如果你用dispatchOnConnection('redis')->onQueue('emails'),它根本不会处理,得去config/horizon.php的environments里把'queues' => ['default', 'emails']加进去 - 运行
ps aux | grep horizon,如果只看到 1 个主进程、没有带supervisor-前缀的子进程,说明 Supervisor 没生效;检查配置里是否漏了numprocs=4,然后必须执行sudo supervisorctl reread && sudo supervisorctl update && sudo supervisorctl start horizon: - Redis 连接失败也会表现为 waiting 不动;试下
redis-cli -h 127.0.0.1 -p 6379 LLEN queues:default,如果报错或返回(error),先查config/database.php里的redis.default配置和.env中的REDIS_HOST/REDIS_PASSWORD
Redis 内存暴涨、horizon:clear 不起效:trim 配置没生效 or Cluster 不支持
高频短任务跑几天后,redis-cli info memory 显示 used_memory 飙升,但 php artisan horizon:clear 执行完没变化——问题出在配置粒度和底层限制上。
-
'recent' => 1000只控制 UI 展示条数,不影响 Redis 实际存储;真正删数据靠的是'completed' => 1000和'failed' => 1000,它们分别对应horizon:recent_jobs和horizon:failed_jobs这两个 key 的最大长度 -
php artisan horizon:terminate不清 Redis,只让 worker 优雅退出;必须配合horizon:clear定期执行(比如 crontab 每小时一次) - 如果用的是 Redis Cluster 或哨兵模式,Horizon 会直接报
ERR unknown command `evalsha`;它目前(截至 2026 年 5 月)**不支持集群拓扑**,必须切回单机 Redis 或加一层 Proxy
监控积压却告不了警:waiting() 返回值滞后 or 队列前缀不一致
你写了 Artisan 命令调 Horizon::stats()->waiting() 判断积压,但告警总延迟几分钟甚至不触发——因为这个值来自 Horizon 自己缓存的统计,不是实时 Redis 状态。
- 若需秒级响应,绕过 Horizon,直接用
redis-cli LLEN queues:default;注意确认前缀:默认是queues:,但可通过HORIZON_PREFIX环境变量或config/horizon.php中的prefix修改 -
Horizon::stats()每 5 秒更新一次,且只统计被 Horizon worker 监听的队列;如果你有部分任务走queue:work,它完全看不到 - 别只盯一个队列;多个业务线可能用了不同队列名(
notifications,exports),得逐个查LLEN queues:notifications,否则积压藏在盲区
最常被忽略的一点:Horizon 的 “success” 状态仅表示任务被 worker 取出并执行完毕,哪怕 handle() 里抛了未捕获异常、数据库事务回滚、HTTP 请求 500,只要没崩掉整个进程,它就标 green。真要判断业务成败,得结合日志、失败表、或在任务里主动上报状态。











