Skip to content
赞助商赞助商赞助商
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

Laravel Horizon

介绍

NOTE

在深入了解 Laravel Horizon 之前,您应该先熟悉 Laravel 的基本队列服务。Horizon 增强了 Laravel 的队列,提供了额外的功能,如果您不熟悉 Laravel 提供的基本队列功能,可能会感到困惑。

Laravel Horizon 为您的 Laravel 驱动的 Redis 队列 提供了一个美观的仪表板和代码驱动的配置。Horizon 允许您轻松监控队列系统的关键指标,如任务吞吐量、运行时间和任务失败。

使用 Horizon 时,所有的队列工作者配置都存储在一个简单的配置文件中。通过在版本控制文件中定义应用程序的工作者配置,您可以在部署应用程序时轻松扩展或修改应用程序的队列工作者。

安装

NOTE

Laravel Horizon 要求您使用 Redis 来驱动您的队列。因此,您应该确保在应用程序的 config/queue.php 配置文件中将队列连接设置为 redis

您可以使用 Composer 包管理器将 Horizon 安装到您的项目中:

php
composer require laravel/horizon

安装 Horizon 后,使用 horizon:install Artisan 命令发布其资产:

php
php artisan horizon:install

配置

发布 Horizon 的资产后,其主要配置文件将位于 config/horizon.php。此配置文件允许您配置应用程序的队列工作者选项。每个配置选项都包含其用途的描述,因此请务必彻底探索此文件。

NOTE

Horizon 在内部使用名为 horizon 的 Redis 连接。此 Redis 连接名称是保留的,不应分配给 database.php 配置文件中的其他 Redis 连接或 horizon.php 配置文件中的 use 选项的值。

环境

安装后,您应该熟悉的主要 Horizon 配置选项是 environments 配置选项。此配置选项是一个数组,包含应用程序运行的环境,并为每个环境定义工作者进程选项。默认情况下,此条目包含 productionlocal 环境。但是,您可以根据需要添加更多环境:

php
'environments' => [
    'production' => [
        'supervisor-1' => [
            'maxProcesses' => 10,
            'balanceMaxShift' => 1,
            'balanceCooldown' => 3,
        ],
    ],

    'local' => [
        'supervisor-1' => [
            'maxProcesses' => 3,
        ],
    ],
],

启动 Horizon 时,它将使用应用程序运行的环境的工作者进程配置选项。通常,环境由 APP_ENV 环境变量 的值确定。例如,默认的 local Horizon 环境配置为启动三个工作者进程,并自动平衡分配给每个队列的工作者进程数量。默认的 production 环境配置为启动最多 10 个工作者进程,并自动平衡分配给每个队列的工作者进程数量。

NOTE

您应该确保 horizon 配置文件的 environments 部分包含计划在其上运行 Horizon 的每个环境的条目。

监督者

如您在 Horizon 的默认配置文件中所见。每个环境可以包含一个或多个“监督者”。默认情况下,配置文件将此监督者定义为 supervisor-1;但是,您可以随意命名您的监督者。每个监督者本质上负责“监督”一组工作者进程,并负责在队列之间平衡工作者进程。

如果您希望为应用程序使用的某个队列定义不同的平衡策略或工作者进程计数,您可以为给定环境添加额外的监督者。

默认值

在 Horizon 的默认配置文件中,您会注意到一个 defaults 配置选项。此配置选项指定应用程序监督者的默认值。监督者的默认配置值将合并到每个环境的监督者配置中,允许您在定义监督者时避免不必要的重复。

平衡策略

与 Laravel 的默认队列系统不同,Horizon 允许您从三种工作者平衡策略中进行选择:simpleautofalsesimple 策略是配置文件的默认策略,将传入的任务均匀地分配给工作者进程:

php
'balance' => 'simple',

auto 策略根据队列的当前工作负载调整每个队列的工作者进程数量。例如,如果您的 notifications 队列有 1,000 个待处理任务,而您的 render 队列为空,Horizon 将为您的 notifications 队列分配更多工作者,直到队列为空。

使用 auto 策略时,您可以定义 minProcessesmaxProcesses 配置选项,以控制 Horizon 应该扩展和缩减的工作者进程的最小和最大数量:

php
'environments' => [
    'production' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue' => ['default'],
            'balance' => 'auto',
            'minProcesses' => 1,
            'maxProcesses' => 10,
            'balanceMaxShift' => 1,
            'balanceCooldown' => 3,
            'tries' => 3,
        ],
    ],
],

balanceMaxShiftbalanceCooldown 配置值用于确定 Horizon 将多快地扩展以满足工作者需求。在上面的示例中,每三秒最多创建或销毁一个新进程。您可以根据应用程序的需要自由调整这些值。

balance 选项设置为 false 时,将使用默认的 Laravel 行为,即按配置中列出的顺序处理队列。

仪表板授权

Horizon 在 /horizon URI 处公开一个仪表板。默认情况下,您只能在 local 环境中访问此仪表板。但是,在您的 app/Providers/HorizonServiceProvider.php 文件中,有一个授权门定义。此授权门控制在非本地环境中访问 Horizon 的权限。您可以根据需要修改此门以限制对 Horizon 安装的访问:

php
/**
 * 注册 Horizon 门。
 *
 * 此门决定谁可以在非本地环境中访问 Horizon。
 *
 * @return void
 */
protected function gate()
{
    Gate::define('viewHorizon', function ($user) {
        return in_array($user->email, [
            'taylor@laravel.com',
        ]);
    });
}

替代身份验证策略

请记住,Laravel 会自动将经过身份验证的用户注入到门闭包中。如果您的应用程序通过其他方法(如 IP 限制)提供 Horizon 安全性,则您的 Horizon 用户可能不需要“登录”。因此,您需要将上面的 function ($user) 闭包签名更改为 function ($user = null),以强制 Laravel 不要求身份验证。

升级 Horizon

升级到 Horizon 的新主要版本时,您需要仔细查看升级指南。此外,升级到任何新的 Horizon 版本时,您应该重新发布 Horizon 的资产:

php
php artisan horizon:publish

为了保持资产的最新状态并避免将来更新中的问题,您可以将 horizon:publish 命令添加到应用程序的 composer.json 文件中的 post-update-cmd 脚本中:

php
{
    "scripts": {
        "post-update-cmd": [
            "@php artisan horizon:publish --ansi"
        ]
    }
}

运行 Horizon

一旦您在应用程序的 config/horizon.php 配置文件中配置了监督者和工作者,您可以使用 horizon Artisan 命令启动 Horizon。此单个命令将启动当前环境的所有配置的工作者进程:

php
php artisan horizon

您可以暂停 Horizon 进程,并使用 horizon:pausehorizon:continue Artisan 命令指示其继续处理任务:

php
php artisan horizon:pause

php artisan horizon:continue

您还可以使用 horizon:pause-supervisorhorizon:continue-supervisor Artisan 命令暂停和继续特定的 Horizon 监督者

php
php artisan horizon:pause-supervisor supervisor-1

php artisan horizon:continue-supervisor supervisor-1

您可以使用 horizon:status Artisan 命令检查 Horizon 进程的当前状态:

php
php artisan horizon:status

您可以使用 horizon:terminate Artisan 命令优雅地终止 Horizon 进程。任何当前正在处理的任务将被完成,然后 Horizon 将停止执行:

php
php artisan horizon:terminate

部署 Horizon

当您准备将 Horizon 部署到应用程序的实际服务器时,您应该配置一个进程监视器来监视 php artisan horizon 命令,并在意外退出时重新启动它。别担心,我们将在下面讨论如何安装进程监视器。

在应用程序的部署过程中,您应该指示 Horizon 进程终止,以便它将由您的进程监视器重新启动并接收您的代码更改:

php
php artisan horizon:terminate

安装 Supervisor

Supervisor 是 Linux 操作系统的进程监视器,如果您的 horizon 进程停止执行,它将自动重新启动。要在 Ubuntu 上安装 Supervisor,您可以使用以下命令。如果您不使用 Ubuntu,您可以使用操作系统的包管理器安装 Supervisor:

php
sudo apt-get install supervisor

NOTE

如果自己配置 Supervisor 听起来很复杂,可以考虑使用 Laravel Forge,它会自动为您的 Laravel 项目安装和配置 Supervisor。

Supervisor 配置

Supervisor 配置文件通常存储在服务器的 /etc/supervisor/conf.d 目录中。在此目录中,您可以创建任意数量的配置文件,指示 Supervisor 如何监视您的进程。例如,让我们创建一个 horizon.conf 文件来启动和监视 horizon 进程:

php
[program:horizon]
process_name=%(program_name)s
command=php /home/forge/example.com/artisan horizon
autostart=true
autorestart=true
user=forge
redirect_stderr=true
stdout_logfile=/home/forge/example.com/horizon.log
stopwaitsecs=3600

NOTE

您应该确保 stopwaitsecs 的值大于最长运行任务消耗的秒数。否则,Supervisor 可能会在任务完成处理之前终止任务。

启动 Supervisor

创建配置文件后,您可以使用以下命令更新 Supervisor 配置并启动监视的进程:

php
sudo supervisorctl reread

sudo supervisorctl update

sudo supervisorctl start horizon

NOTE

有关运行 Supervisor 的更多信息,请查阅 Supervisor 文档

标签

Horizon 允许您为任务分配“标签”,包括邮件、广播事件、通知和排队的事件监听器。实际上,Horizon 会根据附加到任务的 Eloquent 模型智能地自动标记大多数任务。例如,看看以下任务:

php
<?php

namespace App\Jobs;

use App\Models\Video;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class RenderVideo implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * 视频实例。
     *
     * @var \App\Models\Video
     */
    public $video;

    /**
     * 创建一个新的任务实例。
     *
     * @param  \App\Models\Video  $video
     * @return void
     */
    public function __construct(Video $video)
    {
        $this->video = $video;
    }

    /**
     * 执行任务。
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

如果此任务使用 id 属性为 1App\Models\Video 实例排队,它将自动接收标签 App\Models\Video:1。这是因为 Horizon 将在任务的属性中搜索任何 Eloquent 模型。如果找到 Eloquent 模型,Horizon 将使用模型的类名和主键智能地标记任务:

php
use App\Jobs\RenderVideo;
use App\Models\Video;

$video = Video::find(1);

RenderVideo::dispatch($video);

手动标记任务

如果您希望手动定义队列对象的标签,可以在类上定义一个 tags 方法:

php
class RenderVideo implements ShouldQueue
{
    /**
     * 获取应分配给任务的标签。
     *
     * @return array
     */
    public function tags()
    {
        return ['render', 'video:'.$this->video->id];
    }
}

通知

NOTE

在配置 Horizon 以发送 Slack 或 SMS 通知时,您应该查看相关通知渠道的先决条件

如果您希望在队列等待时间较长时收到通知,可以使用 Horizon::routeMailNotificationsToHorizon::routeSlackNotificationsToHorizon::routeSmsNotificationsTo 方法。您可以从应用程序的 App\Providers\HorizonServiceProviderboot 方法中调用这些方法:

php
/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    parent::boot();

    Horizon::routeSmsNotificationsTo('15556667777');
    Horizon::routeMailNotificationsTo('example@example.com');
    Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
}

配置通知等待时间阈值

您可以在应用程序的 config/horizon.php 配置文件中配置多少秒被视为“长等待”。此文件中的 waits 配置选项允许您控制每个连接/队列组合的长等待阈值:

php
'waits' => [
    'redis:default' => 60,
    'redis:critical,high' => 90,
],

指标

Horizon 包含一个指标仪表板,提供有关任务和队列等待时间和吞吐量的信息。为了填充此仪表板,您应该配置 Horizon 的 snapshot Artisan 命令通过应用程序的调度器每五分钟运行一次:

php
/**
 * 定义应用程序的命令调度。
 *
 * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
 * @return void
 */
protected function schedule(Schedule $schedule)
{
    $schedule->command('horizon:snapshot')->everyFiveMinutes();
}

删除失败的任务

如果您希望删除失败的任务,可以使用 horizon:forget 命令。horizon:forget 命令接受失败任务的 ID 或 UUID 作为其唯一参数:

php
php artisan horizon:forget 5

清除队列中的任务

如果您希望从应用程序的默认队列中删除所有任务,可以使用 horizon:clear Artisan 命令:

php
php artisan horizon:clear

您可以提供 queue 选项以从特定队列中删除任务:

php
php artisan horizon:clear --queue=emails