Skip to content

Laravel Horizon

介绍

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

所有的工作者配置都存储在一个简单的配置文件中,使您的配置可以保存在源代码控制中,便于整个团队协作。

安装

exclamation

由于其使用异步进程信号,Horizon 需要 PHP 7.1+。其次,您应确保在 queue 配置文件中将队列驱动程序设置为 redis

您可以使用 Composer 将 Horizon 安装到您的 Laravel 项目中:

php
composer require laravel/horizon "^2.0"

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

php
php artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider"

配置

发布 Horizon 的资产后,其主要配置文件将位于 config/horizon.php。此配置文件允许您配置工作者选项,每个配置选项都包含其目的的描述,因此请务必仔细查看此文件。

平衡选项

Horizon 允许您从三种平衡策略中进行选择:simpleautofalse。默认的 simple 策略将传入的作业均匀地分配到各个进程:

php
'balance' => 'simple',

auto 策略根据队列的当前工作负载调整每个队列的工作者进程数量。例如,如果您的 notifications 队列有 1,000 个等待作业,而您的 render 队列为空,Horizon 将为您的 notifications 队列分配更多的工作者,直到其为空。当 balance 选项设置为 false 时,将使用默认的 Laravel 行为,即按配置中列出的顺序处理队列。

仪表板认证

Horizon 在 /horizon 处公开一个仪表板。默认情况下,您只能在 local 环境中访问此仪表板。要为仪表板定义更具体的访问策略,您应使用 Horizon::auth 方法。auth 方法接受一个回调,该回调应返回 truefalse,指示用户是否应有权访问 Horizon 仪表板。通常,您应在 AppServiceProviderboot 方法中调用 Horizon::auth

php
Horizon::auth(function ($request) {
    // return true / false;
});

运行 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:terminate Artisan 命令优雅地终止您机器上的主 Horizon 进程。Horizon 当前正在处理的任何作业将完成,然后 Horizon 将退出:

php
php artisan horizon:terminate

部署 Horizon

如果您将 Horizon 部署到实时服务器,您应配置一个进程监视器来监视 php artisan horizon 命令,并在其意外退出时重新启动它。当将新代码部署到服务器时,您需要指示主 Horizon 进程终止,以便进程监视器可以重新启动它并接收您的代码更改。

Supervisor 配置

如果您使用 Supervisor 进程监视器来管理您的 horizon 进程,以下配置文件应足够:

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

如果您不愿意自己管理服务器,请考虑使用 Laravel Forge。Forge 提供 PHP 7+ 服务器,具备运行现代、强大的 Laravel 应用程序与 Horizon 所需的一切。

标签

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

php
<?php

namespace App\Jobs;

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

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

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

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

    /**
     * 执行作业。
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

如果此作业使用 id1App\Video 实例排队,它将自动接收标签 App\Video:1。这是因为 Horizon 将检查作业的属性以查找任何 Eloquent 模型。如果找到 Eloquent 模型,Horizon 将使用模型的类名和主键智能地标记作业:

php
$video = App\Video::find(1);

App\Jobs\RenderVideo::dispatch($video);

手动标记

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

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

通知

lightbulb

在使用通知之前,您应将 guzzlehttp/guzzle Composer 包添加到您的项目中。在配置 Horizon 以发送 SMS 通知时,您还应查看 Nexmo 通知驱动程序的先决条件

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

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

配置通知等待时间阈值

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

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

指标

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

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