介绍 Horizon 为你的 Laravel Redis 队列提供了一个美观的控制面板和代码驱动的配置;它可以方便的监控队列系统的关键指标:任务吞吐量、运行时间、工作故障。 所有的 worker 配置存储在一个简单的配置文件中,你可以在整个团队都可以进行协作的地方进行源码控制。 安装 注意:确保队列连接在 queue 配置文件的 redis 项已经正确设置。 可以使用 Composer 将 Horizon 安装到你的 Laravel 项目里: ``` composer require laravel/horizon ``` Horizon 安装之后,使用 horizon:install Artisan 命令发布资源: ``` php artisan horizon:install ``` 配置 Horizon 资源发布之后,其主要配置文件会被分配到 config/horizon.php 文件。可以用这个配置文件配置工作选项,每个配置选项包含一个用途描述,请务必仔细研究这个文件。 注意:要确保 horizon 配置文件的 environments 部分包含你了你计划在 horizon 上运行的每个环境选项。 Balance 选项 Horizon 允许你从三个平衡策略中进行选择:simple, auto, 和 false。simple 策略是配置文件的默认选项,它会在进程之间平均分配进入的任务: ``` 'balance' => 'simple', ``` auto 策略根据队列的当前工作负载来调整每个队列的工作进程数量。举个例子,如果你的 notifications 队列有 1000 个等待的任务,而你的 render 队列是空的,那么 Horizon 将为 notifications 队列分配更多的工作线程,直到队列为空。当 balance 选项被设置为 false 时,将使用默认的 Laravel 行为,它按照配置中列出的顺序处理队列。 当使用 auto 策略时,你可以定义 minProcesses 和 maxProcesses 的配置选项来控制进程的最小和最大数量: ``` 'environments' => [ 'production' => [ 'supervisor-1' => [ 'connection' => 'redis', 'queue' => ['default'], 'balance' => 'auto', 'minProcesses' => 1, 'maxProcesses' => 10, 'balanceMaxShift' => 1, 'balanceCooldown' => 3, 'tries' => 3, ], ], ], ``` balanceMaxShift 和 balanceCooldown 配置项可以确定 Horizon 将以多快的速度扩展进程,在上面的示例中,每 3 秒钟最多创建或销毁一个新进程,你可以根据应用程序的需要随意调整这些值。 任务清理 horizon 配置文件允许你配置最近的和失败的任务应该持续多长时间 (以分钟为单位)。默认情况下,最近的作业保存一个小时,而失败的作业保留一周: ``` 'trim' => [ 'recent' => 60, 'failed' => 10080, ], ``` 控制面板授权 Horizon 在 /horizon 上显示了一个控制面板。默认情况下,你只能在 local 环境中访问这个面板。在你的 app/Providers/HorizonServiceProvider.php 文件中,有一个 gate 方法。控制着在非本地环境中对 Horizon 的访问。你可以根据需要修改此方法,来限制对 Horizon 的访问: ``` /** * 注册 Horizon 授权 * * 此方法决定了谁可以在非本地环境中访问 Horizon * * @return void */ protected function gate() { Gate::define('viewHorizon', function ($user) { return in_array($user->email, [ 'taylor@laravel.com', ]); }); } ``` 注意:Laravel 会自动将经过 authenticated 的用户注入到***(Gate)闭包中。如果你的应用程序通过其他方法(例如 IP 限制)提供 Horizon 安全性保障,那么你访问 Horizon 用户可能不需要实现这个「登录」动作。因此,你需要将上面的 function ($user) 更改为 function ($user = null) 以强制 Laravel 跳过身份验证。 升级 Horizon 当你升级到 Horizon 的一个新的主要版本时,你需要仔细阅读 升级指南。 此外,升级到新的 Horizon 版本时,你应该重新发布 Horizon 资源: ``` php artisan horizon:publish ``` 为了使资源文件保持最新并避免以后的更新中出现问题,你可以将以下命令添加到 composer.json 文件中的 post-update-cmd 脚本中: ``` { "scripts": { "post-update-cmd": [ "@php artisan horizon:publish --ansi" ] } } ``` 运行 Horizon 在 config/horizon.php 中配置了你的 workers 之后,你可以使用 horizon Artisan 命令启动 Horizon。只需这一个命令你就可以启动你的所有已配置的 workers: ``` php artisan horizon ``` 你可以暂停 Horizon 进程,并使用 horizon:pause 和 horizon:continue Artisan 命令指示它继续处理任务: ``` php artisan horizon:pause php artisan horizon:continue ``` 可以使用 horizon:status Artisan 命令检查 Horizon 进程的当前状态: ``` php artisan horizon:status ``` 你可以使用 horizon:terminate Artisan 命令优雅地终止机器上的主 Horizon 进程。Horizon 会等当前正在处理的所有任务都完成后退出: ``` php artisan horizon:terminate ``` 部署 Horizon 如果要将 Horizon 部署到一个正在运行的服务器上,应该配置一个进程监视器来监视 php artisan horizon 命令,并在它意外退出时重新启动它。在将新代码部署到服务器时,你需要终止 Horizon 主进程,以便进程监视器重新启动它并接收代码的更改。 安装 Supervisor Supervisor 是一个用于 Linux 操作系统的进程监视器。如果 Horizon 进程被退出或终止,Supervisor 将自动重启你的 Horizon 进程。如果要在 Ubuntu 上安装 Supervisor,你可以使用以下命令: ``` sudo apt-get install supervisor ``` 技巧:如果你觉得自己配置 Supervisor 难如登天,可以考虑使用 Laravel Forge,它将自动为你的 Laravel 项目安装和配置 Supervisor。 Supervisor 配置 Supervisor 配置文件通常存储在 /etc/supervisor/conf.d 目录下。在此目录中,你可以创建任意数量的配置文件,这些配置文件会告诉 supervisor 如何监视你的进程。例如,让我们创建一个 horizon.conf 文件,它启动并监视一个 horizon 进程: ``` [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 stopwaitsecs=3600 ``` 注意:要确保 stopwaitsecs 的值大于运行时间最长的任务所消耗的秒数。否则,Supervisor 可能会在工作完成前终止任务。 启动 Supervisor 创建了配置文件后,可以使用以下命令更新 Supervisor 配置并启动进程: ``` sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start horizon ``` 关于 Supervisor 的更多信息,可以查阅 Supervisor 文档。 标记 Horizon 允许你将 tags 分配给任务,包括邮件、事件广播、通知和排队的事件***。实际上,Horizon 会根据附加到作业上的有 Eloquent 模型,智能地、自动地标记大多数任务。例如,看看下面的任务: ``` <?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; /** * video 实例 * * @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() { // } } ``` 如果此任务与 App\Models\Video 实例一起排队,且该实例的 id 为 1,则该作业将自动接收 App\Models\Video:1 标记。这是因为 Horizon 将为任何有 Eloquent 的模型检查任务的属性。如果找到了有 Eloquent 的模型,Horizon 将智能地使用模型的类名和主键标记任务: ``` $video = App\Models\Video::find(1); App\Jobs\RenderVideo::dispatch($video); ``` 手动标记 如果你想手动定义你的一个队列对象的标签,你可以在类上定义一个 tags 方法: ``` class RenderVideo implements ShouldQueue { /** * 获取应该分配给任务的标记 * * @return array */ public function tags() { return ['render', 'video:'.$this->video->id]; } } ``` 通知 注意: 当配置 Horizon 发送 Slack 或 SMS 通知时,你应该查看 相关通知驱动程序的先决条件。 如果你希望在一个队列有较长的等待时间时得到通知,你可以使用 Horizon::routeMailNotificationsTo, Horizon::routeSlackNotificationsTo, 和 Horizon::routeSmsNotificationsTo 方法。你可以从你的应用程序的 HorizonServiceProvider 调用这些方法: ``` Horizon::routeMailNotificationsTo('example@example.com'); Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel'); Horizon::routeSmsNotificationsTo('15556667777'); ``` 配置通知等待时间阈值 你可以在 config/horizon.php 的配置文件中配置多少秒算是「长等待」。你可以用该文件中的 waits 配置选项控制每个 连接 / 队列 组合的长等待阈值: ``` 'waits' => [ 'redis:default' => 60, 'redis:critical,high' => 90, ], ``` 指标 Horizon 有一个指标控制面板,它提供了任务和队列的等待时间和吞吐量等信息。要让这些信息显示在这个控制面板上,你应该配置 Horizon 的 snapshot Artisan 命令,通过你的应用程序的 调度器 每五分钟运行一次: ``` /** * 定义应用程序的命令调度 * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @return void */ protected function schedule(Schedule $schedule) { $schedule->command('horizon:snapshot')->everyFiveMinutes(); } ```