首页
/ Coolify 中的 Horizon 作业标签与静默机制:Eloquent 自动标签、tags() 定制与 silenced 降噪

Coolify 中的 Horizon 作业标签与静默机制:Eloquent 自动标签、tags() 定制与 silenced 降噪

2026-09-06 23:32:13作者:劳婵绚Shirley

Coolify 作为基于 Laravel 的自托管 PaaS,使用 Laravel Horizon(composer.json 中锁定 laravel/horizon: ^5.48.2)监控其部署、备份等队列作业。本文围绕 Horizon 的作业标签(Tags)与静默(Silencing)机制展开:讲清 Eloquent 模型作业如何被自动打上 ModelClass:id 标签、何时需要手写 tags() 方法,以及 silenced / silenced_tags 两个配置项如何为已完成作业列表降噪。读完本文,你可以在 Horizon 面板中按标签过滤作业、复用 Coolify 源码中"用标签反查业务记录"的成熟做法,并知道如何把高频噪音作业从面板中隐藏而不影响其执行。

一、标签与静默在 Coolify 队列体系中的位置

Coolify 的后台作业(部署 ApplicationDeploymentJob、数据库备份 DatabaseBackupJob、哨兵检查 CheckAndStartSentinelJob 等)全部通过 Redis 队列驱动、由 Horizon 托管。config/horizon.php 定义了名为 s6 的监督器,队列默认取 high,default(由 HORIZON_QUEUES 环境变量控制),并按 production / local 环境配置了 autoScalingStrategy => 'size' 的进程弹性伸缩(maxProcesses 默认 4)。

在这个体系里,标签与静默解决的是两类问题:

  • 可观测性:标签让每个作业携带业务上下文(操作了哪台服务器、哪条部署记录),在 Horizon 面板中可直接按标签过滤、定位;
  • 降噪silenced / silenced_tags 让高频、低价值的作业从"已完成"列表中消失,避免真正需要关注的部署作业被淹没。

需要注意的是,这两个机制都只作用于 Horizon 的展示层:标签改变的是作业的元数据,静默改变的是面板过滤结果,均不改变作业本身是否执行。

二、Eloquent 模型作业会被自动打标签,无需任何额外代码

这是标签机制中最容易被忽略、也最实用的行为:如果一个作业的构造函数接收 Eloquent 模型实例,Horizon 会自动为该作业打上 ModelClass:id 形式的标签,例如 App\Models\User:42。这些标签可以直接在面板中用于过滤,无需修改作业类本身。

Coolify 源码中大量作业正是这种模式,自动标签会直接生效:

也就是说,无需任何改动,你在 Horizon 面板中筛选 App\Models\Server:7,就能看到所有针对 7 号服务器执行的检查、清理、代理连接作业。

源码印证:Coolify 用自动标签反查业务记录

自动标签不只是面板上的好看——Coolify 在 HorizonServiceProvider 中监听 Horizon 的 JobReserved 事件,直接解析作业载荷中的 tags 字段来打通"Horizon 作业 ID ↔ 部署记录"的映射:

Event::listen(function (JobReserved $event) {
    $payload = $event->payload->decoded;
    $jobName = $payload['displayName'];
    if ($jobName === 'App\Jobs\ApplicationDeploymentJob') {
        $tags = $payload['tags'];
        $id = $payload['id'];
        $deploymentQueueId = collect($tags)->first(function ($tag) {
            return str_contains($tag, 'App\Models\ApplicationDeploymentQueue');
        });
        if (blank($deploymentQueueId)) {
            return;
        }
        $deploymentQueueId = explode(':', $deploymentQueueId)[1];
        $deploymentQueue = ApplicationDeploymentQueue::find($deploymentQueueId);
        $deploymentQueue->update([
            'horizon_job_id' => $id,
        ]);
    }
});

这段逻辑印证了两个事实:其一,作业载荷中的 tags 数组包含自动标签,格式为 标签键:值,可用 explode(':', $tag)[1] 取出 ID;其二,Coolify 借此在作业被 worker 领取的瞬间,就把 horizon_job_id 写入 ApplicationDeploymentQueue 记录,从而让前端部署详情页能跳转到 Horizon 面板中对应的作业。这是"标签即查询句柄"的典型用法。

三、何时手写 tags() 方法:Coolify 的自定义标签实践

自动标签覆盖了"构造函数里传入的模型"这一场景,但当你需要标签携带的信息不是构造参数、或者需要固定格式的识别标签时,就应添加 tags() 方法。参考文档给出的原则很明确:只有在需要自动标签之外的自定义标签时,才添加 tags() 方法

Coolify 的 ApplicationDeploymentJob 就是一个例子——它的构造函数只接收一个 int 主键(而非 Eloquent 实例),因此自动标签无法表达"这是哪次部署",于是手写:

public function tags()
{
    // Do not remove this one, it needs to properly identify which worker is running the job
    return ['App\Models\ApplicationDeploymentQueue:'.$this->application_deployment_queue_id];
}

public function __construct(public int $application_deployment_queue_id)
{
    $this->onQueue(deployment_queue());
    // ...
}

源码注释写得很直白:"不要删除这个标签,它需要正确识别哪个 worker 正在运行该作业"。这个标签正是上面第二节中 JobReserved 监听器依赖的键——两处代码互为印证,构成一条完整的链路:作业侧声明标签 → 载荷携带标签 → 服务提供者解析标签回写业务表

从源码结构看,手动 tags() 返回的标签与自动标签在格式上保持一致(类名:id),因此面板过滤、事件监听等消费方可以用同一套 str_contains / explode(':') 逻辑处理两类标签。

四、silenced:从"已完成"列表隐藏作业,但不影响执行

config/horizon.php 中的 silenced 选项(config/horizon.php)用于将指定作业类从 Horizon 面板的已完成作业视图中移除:

/*
| Silenced Jobs
|
| Silencing a job will instruct Horizon to not place the job in the list
| of completed jobs within the Horizon dashboard. This setting may be
| used to fully remove any noisy jobs from the completed jobs list.
|
*/
'silenced' => [
    // App\Jobs\ExampleJob::class,
],

当前 Coolify 仓库中该数组为空(仅保留注释掉的示例),但用法非常直接:把作业类完整类名加入数组即可。

必须强调的边界(这也是参考文档反复提醒的点):silenced面板降噪工具,不是禁用手段。被静默的作业仍然会正常入队、被 worker 领取、正常执行,只是不再出现在已完成作业列表中。如果你想让某个作业停止运行,应该从业务侧不再派发它,或者删除/注释其调度逻辑,而不是把它加进 silenced

典型适用场景是那些每次请求都会触发、量大但无需逐条查看的作业(例如心跳检查类、状态刷新类作业)——把它们静默后,s6 监督器下的已完成列表就能让 ApplicationDeploymentJob 这类关键作业的成败记录保持可读。

五、silenced_tags:按标签类别批量静默

按类静默只能逐个指定作业类;而 silenced_tags 提供更粗粒度但更省事的开关:任何携带匹配标签字符串的作业都会被隐藏出已完成列表

以 Coolify 的标签体系举例,假设多个通知、遥测类作业都被打上 notifications 标签(通过第二节描述的模型自动标签或第三节的 tags() 方法),那么将该标签类别加入 silenced_tags,即可一次性隐藏整个类别的作业,而不是逐一枚举作业类名。这对应参考文档的表述:"适合静默一类作业,例如所有被打上 notifications 标签的作业,而非静默具体某个类"。

两者取舍可以归纳为:

需求 应使用的选项 匹配粒度
隐藏某一个(几个)特定作业类 silenced 数组 作业类全名(::class
隐藏一类作业(按标签类别) silenced_tags 标签字符串
让作业不再运行 两者都不行 需从派发/调度侧处理

需要说明的前提:当前仓库的 config/horizon.php 仅内置了 silenced 键;silenced_tags 是 Horizon 配置结构中的兄弟选项,若你的 Horizon 版本配置文件中不存在该键,需要按版本文档确认其可用性后再添加,不要凭空假设旧版本支持。

六、实践要点小结

  1. 先利用自动标签,再考虑写代码:构造函数接收 Eloquent 模型的作业(如 CheckAndStartSentinelJobDatabaseBackupJob)已经自带 ModelClass:id 标签,面板过滤即可使用,无需任何改动。
  2. 手写 tags() 的唯一理由是携带自动标签之外的信息(参考 ApplicationDeploymentJob::tags());一旦写出标签并被其他代码依赖(如 HorizonServiceProvider 中的 JobReserved 监听器),注释中应像 Coolify 那样明确警示"勿删"。
  3. 静默只影响展示silencedsilenced_tags 都只让作业从"已完成"视图中消失,作业照常执行;不要把它们当作禁用或限流手段。
  4. 标签格式即契约ModelClass:id 的冒号分隔格式是消费侧(explode(':', $tag)str_contains)解析的前提,自定义标签建议沿用同一格式,方便统一处理。
  5. 改动前先读 config/horizon.php:Coolify 的监督器配置(s6HORIZON_QUEUES、环境级进程伸缩)与 silenced 同处一个文件,理解当前结构再动配置,可避免误改队列与伸缩参数。

本文依据的来源:参考文档 .claude/skills/configuring-horizon/references/tags.md(标签与静默的原始说明)、技能索引 SKILL.md,以及仓库内的 config/horizon.phpapp/Providers/HorizonServiceProvider.phpapp/Jobs/ApplicationDeploymentJob.php 等实现文件。

登录后查看全文
热门项目推荐
相关项目推荐