horizon 面板正常运行需 redis 连通、定时快照(horizon:snapshot)、权限放行和独立进程四者同时就位;缺一则导致白屏、指标停滞或失败任务不显示。

Horizon 面板不是装完就能用的,它依赖 Redis 连通性、定时快照、权限放行和独立进程三者同时就位;缺一不可,否则页面空白、吞吐量冻结或失败任务不显示都是常态。
为什么 /horizon 页面 404 或白屏?
最常见原因是路由未注册或权限拦截过严。Horizon 默认只在 APP_ENV=local 下自动注册路由,生产环境必须手动放开。
- 检查
config/horizon.php中enabled是否为true(设成false会静默禁用全部功能) - 确认
App\Providers\HorizonServiceProvider::class在config/app.php的providers数组中且未被注释 - 在
AppServiceProvider::boot()中添加授权回调:Horizon::auth(fn ($request) => true);(临时测试可用,上线前替换为真实鉴权逻辑) - 新版 Horizon(v5.10+)推荐用
php artisan horizon:install初始化,它会自动创建配置、迁移和软链接资源,比vendor:publish更可靠
吞吐量图表不动或延迟严重?
吞吐量、延迟、活跃任务数等指标全靠 horizon:snapshot 命令定时采集并写入 Redis 和数据库,这个命令默认由 Laravel Scheduler 每分钟执行一次。没配调度,数据就永远停在初始状态。
- 在
app/Console/Kernel.php的schedule()方法中加入:$schedule->command('horizon:snapshot')->everyMinute(); - 确认服务器 cron 正确指向:
* * * * * cd /path/to/project && php artisan schedule:run >> /dev/null 2>&1 - 手动运行
php artisan horizon:snapshot观察输出——如果报 Redis 连接超时或权限拒绝,说明底层连接异常,horizon:snapshot失败时通常静默,不会抛错 - 注意:在
APP_ENV=testing下,Horizon 会跳过所有快照收集,测试时切到local或production
失败任务看不到、重试无效或堆栈为空?
Horizon 展示失败任务的前提是:任务确实被 Laravel 队列系统捕获并存入 horizon:failed(Redis)或 failed_jobs(database),而不是直接崩溃退出。
- 确保
config/queue.php中failed配置启用;Redis 驱动下,失败任务默认存进 Redis 的horizon:failed列表,**不是**failed_jobs表——所以php artisan queue:failed不会列出 Horizon 管理的失败任务 - 检查
config/horizon.php中trim配置项,若failed设置过小(如'failed' => 10),旧失败任务会被自动清理,导致面板里“刚失败就消失” - 重试操作本质是把任务从
horizon:failed移回对应队列(如redis:queues:default),若重试后仍不执行,先确认该队列是否在config/horizon.php的queues列表中被监听 - 堆栈为空?检查任务类中是否用了
try/catch吞掉了异常,或在failed()方法里没调用parent::failed($exception),导致 Horizon 无法提取原始错误上下文
启动后无日志、任务不消费或指标全为零?
Horizon 是独立守护进程,它不依赖 queue:work,也不能和 queue:work 共存于同一队列——否则会抢任务、漏执行、指标错乱。
- 确认
.env中QUEUE_CONNECTION=redis,且config/queue.php的redis连接块中connection值与config/database.php的 Redis 配置键名完全一致(比如写成'connection' => 'cache',但database.php里根本没有叫cache的 Redis 配置) - 执行
php artisan tinker后输入Redis::ping(),返回"PONG"才算 Redis 真通;改了配置后必须php artisan config:clear,否则 Horizon 静默加载旧缓存 - 运行
php artisan migrate——horizon:install只生成迁移文件,不执行;它会建horizon_monitoring表(存指标)和failed_jobs表(若不存在) - 启动命令只能是
php artisan horizon(开发)或php artisan horizon --daemon(生产),Supervisor 配置里也必须指向这个命令,绝不能混用queue:work
真正卡住的地方往往不在面板本身,而在 Redis 连通性、快照定时任务是否真在跑、以及 Horizon 进程是否真的在监听你认为它该监听的那个队列——这三个点不验证清楚,调界面样式或改前端 JS 都是白忙。











