如何使Laravel Queue系统在服务器上运行


73

我最近设置了Laravel Queue系统。基本内容是cronjob,该命令调用将作业添加到队列中的命令,并调用第二个发送电子邮件的命令。

当我SSH进入服务器并运行php artisan queue:listen时,系统可以正常工作,但是如果我关闭终端,则监听器将关闭,并且作业堆积起来并排成队列,直到我ssh重新进入并再次运行监听。

使队列系统在后台运行而无需通过ssh保持连接打开的最佳方法是什么?

我尝试运行php artisan queue:work --daemon,它完成了队列中的作业,但是当我关闭终端时,它关闭了连接和后台进程。

Answers:


100

跑步

nohup php artisan queue:work --daemon &

注销时将防止命令退出。

尾部的&符号会导致进程在后台启动,因此您可以继续使用外壳程序,而不必等到脚本完成。

nohup

nohup-运行不受挂断影响的命令,并输出到非tty

这会将信息输出到运行命令的目录中名为nohup.out的文件中。如果您对输出不感兴趣,可以将stdout和stderr重定向到/ dev / null,或者类似地,也可以将其输出到常规laravel日志中。例如

nohup php artisan queue:work --daemon > /dev/null 2>&1 &

nohup php artisan queue:work --daemon > app/storage/logs/laravel.log &

但是,您还应该使用Supervisord之类的方法来确保该服务保持运行状态,并在崩溃/故障后重新启动。


棒极了!我认为这将是公认的答案!我很快就可以测试。谢谢。
零一1年

AWesome..this让我很快乐
萨米特

7
首先,我需要:stackoverflow.com/a/29292637/470749然后nohup php artisan queue:work --daemon > storage/logs/laravel.log &为我工作。注意:如果要终止nohup守护程序,则需要先运行来发现其PID ps -ef |grep artisan。然后,您可以运行kill [pid] stackoverflow.com/q/17385794/470749
Ryan

1
这是一个糟糕的解决方案,因为一旦发出队列:重置工作程序死亡,并且您没有重新启动机制,只需使用有监督的,生成2个工作程序,当数量大时,您将像黄金一样。附带说明,每次更改代码时,都需要重新生成新的worker。
z900collector

2
@ z900collector答案明确指出,您应该使用Supervisord之类的东西,并且总是这样做。
Ben Swinburne

30

您应该使用linux主管

安装非常简单,在Ubuntu上,我可以使用以下命令进行安装:

apt-get install supervisor

主管配置文件位于/etc/supervisor/conf.d目录中。

[program:email-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/laravel-example/artisan queue:work redis --queue=emailqueue --sleep=3 --tries=3
autostart=true
autorestart=true
user=forge
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/laravel-example//storage/logs/supervisord.log

对于每个流程,您应该创建一个新的流程配置文件。使用此配置,侦听器将重试每个作业3次。如果Supervisor失败或系统重新启动,Supervisor还将重新启动监听器。


2
更多说明在这里,digitalocean.com
community / tutorials /…

您好,您能帮我解决吗?我使用supervisord并执行的作业,但不能创建一个文件stackoverflow.com/questions/47715537/...
Irfandi D. Vendy

值得一提的是Laravel记录在案的做事方式:laravel.com/docs/5.6/queues#supervisor-configuration
Martin Joiner

17

命令

nohup php artisan queue:work --daemon &

是正确的,它将允许该过程在关闭SSH连接后继续进行;但是,这只是短期修复。重新启动服务器或任何问题导致进程停止后,您将需要返回并再次运行命令。发生这种情况时,您永远不会知道。它可能会在星期五晚上发生,因此最好实施长期解决方案。

我最终切换到Supervisord,可以轻松地在Ubuntu上安装它

sudo apt-get install supervisor 

对于AWS-AMI或RedHat用户,您可以按照我在此问题中概述的一组说明进行操作:

在AWS AMI Linux服务器上设置Supervisord


您好,您能帮我解决吗?我使用supervisord并执行的作业,但不能创建一个文件stackoverflow.com/questions/47715537/...
Irfandi D. Vendy

1
那么,为什么不接受建议主管的答案呢?
dewwwald

2
该答案仅适用于Ubuntu用户,我的答案链接到一个单独的问题,该问题涉及如何在基于RedHat的发行版上进行设置。此外,我回答了Dev 15 2016,其他仅适用于Ubuntu用户的答案出现在2017
零和一

不必太讲究,但@deewwald可能是指您在此处表示您可能会接受的答案-AFAICT是它发布的第一个(有意义的)答案,它建议使用Supervisor,它并不特定于任何操作系统。
不要惊慌

嗯,我同意答案是有意义的,并回答了问题,但这确实是一个糟糕的解决方案。为了可靠地具有队列过程,应集成某种排序或过程监视器。laravel社区似乎倾向于Supervisor,但是我也看到Monit也成功地使用了它。
零和一

12

来自https://gist.github.com/ivanvermeyen/b72061c5d70c61e86875

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class EnsureQueueListenerIsRunning extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'queue:checkup';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Ensure that the queue listener is running.';

    /**
     * Create a new command instance.
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return void
     */
    public function handle()
    {
        if ( ! $this->isQueueListenerRunning()) {
            $this->comment('Queue listener is being started.');
            $pid = $this->startQueueListener();
            $this->saveQueueListenerPID($pid);
        }

        $this->comment('Queue listener is running.');
    }

    /**
     * Check if the queue listener is running.
     *
     * @return bool
     */
    private function isQueueListenerRunning()
    {
        if ( ! $pid = $this->getLastQueueListenerPID()) {
            return false;
        }

        $process = exec("ps -p $pid -opid=,cmd=");
        //$processIsQueueListener = str_contains($process, 'queue:listen'); // 5.1
        $processIsQueueListener = ! empty($process); // 5.6 - see comments

        return $processIsQueueListener;
    }

    /**
     * Get any existing queue listener PID.
     *
     * @return bool|string
     */
    private function getLastQueueListenerPID()
    {
        if ( ! file_exists(__DIR__ . '/queue.pid')) {
            return false;
        }

        return file_get_contents(__DIR__ . '/queue.pid');
    }

    /**
     * Save the queue listener PID to a file.
     *
     * @param $pid
     *
     * @return void
     */
    private function saveQueueListenerPID($pid)
    {
        file_put_contents(__DIR__ . '/queue.pid', $pid);
    }

    /**
     * Start the queue listener.
     *
     * @return int
     */
    private function startQueueListener()
    {
        //$command = 'php-cli ' . base_path() . '/artisan queue:listen --timeout=60 --sleep=5 --tries=3 > /dev/null & echo $!'; // 5.1
        $command = 'php-cli ' . base_path() . '/artisan queue:work --timeout=60 --sleep=5 --tries=3 > /dev/null & echo $!'; // 5.6 - see comments
        $pid = exec($command);

        return $pid;
    }
}

感谢您的共享,这是确保队列正在运行的独特方式!不错,因为不需要安装新的依赖项,只需要在CRONTAB上使用一个句柄即可。任何权限设置陷阱吗?
零零一分

1
没有权限问题。只需要注意php版本和路径,有时它们与shell不同。共享托管通常会关闭alse exec()。–
哈里·波什

更新为5.6,请参阅链接的注释5.1
哈里·波什

这种用法queue:work意味着没有监听任何代码更改,或者至少需要手动重新启动该过程。但在代码中,我没有看到任何重启..任何想法?
大卫·瓦伦蒂诺

1
这确实保存了我的网站!我无法使用其他人推荐的主管,这种方法很好用。没有任何问题。我确实必须针对我的环境稍微更改命令。
Forseth11

7

1)sudo apt install supervisor

sudo apt-get install supervisor

2)cd /etc/supervisor/conf.d 3)在内部创建新文件

sudo vim queue-worker.conf

文件内容

[program:email-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/laravelproject/artisan queue:work
autostart=true
autorestart=true
user=root
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/html/laravelproject/storage/logs/supervisord.log

4)sudo supervisorctl reread

运行此命令时获取输出queue-worker:available

5)sudo supervisorctl update

运行此命令时获取输出queue-worker:added进程组

其他命令

1)sudo supervisorctl reload

运行此命令时获取输出重新启动主管

2)sudo service supervisor restart


是的,它对我来说是工作,我还尝试了另一种方法,我制定了时间表,每隔5分钟启动我的队列工匠,这也是可行的
专家建议

您在哪个Linux发行版上使用它?
零零一

6

安装主管

sudo apt-get install supervisor

配置主管

步骤1:转到/etc/supervisor/conf.d目录

cd /etc/supervisor/conf.d

步骤2:创建一个工作文件laravel-worker.conf,它将监听队列

sudo nano laravel-worker.conf

*注意:现在假设您的laravel应用位于/var/www/html目录内

project folder is : /var/www/html/LaravelApp

步骤3:将以下代码粘贴到laravel-worker.conf中并保存文件

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/LaravelApp/artisan queue:listen redis --queue=default --sleep=3 --tries=3 
autostart=true
autorestart=true
user=root
numprocs=8
redirect_stderr=true
stdout_logfile= /var/www/html/LaravelApp/storage/logs/worker.log

*注意:这里假设您使用redis进行队列连接

在.env文件中 QUEUE_CONNECTION=redis

command=php /var/www/html/LaravelApp/artisan queue:listen redis

如果您正在使用其他连接,则一般语法为:

command= php [project_folder_path]/artisan queue:listen [connection_name]

[connection_name]可以是syncdatabasebeanstalkdsqsredis中的任何一个

步骤4:创建一个工作文件laravel-schedule.conf,该文件每1分钟(60秒)运行一次artisan schedule:run命令(*您可以根据需要进行更改)

[program:laravel-schedule]
process_name=%(program_name)s_%(process_num)02d
command=/bin/bash -c 'while true; do date && php /var/www/html/LaravelApp/artisan schedule:run; sleep 60; done'
autostart=true
autorestart=true
numprocs=1
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0

步骤5:启动Supervisor:运行以下命令

sudo supervisorctl reread

sudo supervisorctl update

sudo supervisorctl start all

*注意:每当您对任何配置.conf文件进行更改时,请运行上述第5步命令

额外有用的信息:

  • 停止所有主管程序: sudo supervisorctl stop all
  • 重新启动所有supervisorctl进程: sudo supervisorctl restart all

有用的链接:

https://laravel.com/docs/5.8/queues#running-the-queue-worker

http://supervisord.org/index.html


5

对于已经在其生产环境中运行NodeJS的人员。我使用PM2来管理应用程序流程。

# install
npm install -g pm2

# in project dir with your CI or dev setup tool 
# --name gives task a name so that you can later manage it
# -- delimits arguments that get passed to the script
pm2 start artisan --interpreter php --name queue-worker -- queue:work --daemon

我在开发和设置NodeJS时使用Vagrant,并且此过程仅使用内联流浪脚本。

在开发中使用PM2时,可以使用众多观察者之一来管理重启。pm2 restart queue-worker拿起更改即可简单运行。在生产中,我不推荐这种方法,而是选择可以遵循此过程的构建工具。

# 1. stop pm task to ensure that no unexpected behaviour occurs during build
pm2 stop queue-worker
# 2. do your build tasks
...
# 3. restart queue so that it loads the new code
pm2 restart queue-worker

4

使用pm2

我在pm2上运行了JS脚本(高级,Node.js的生产过程管理器)一起运行,这是我唯一。但是现在我有了一个继续运行的过程。

我创建process.yml了一个命令即可同时运行这两个命令。检查第一个将运行php artisan queue: listen

# process.yml at /var/www/ which is root dir of the project
apps:
  # Run php artisan queue:listen to execute queue job
  - script    : 'artisan'
    name      : 'artisan-queue-listen'
    cwd       : '/var/www/'
    args      : 'queue:listen' # or queue:work
    interpreter : 'php'

  # same way add any other script if any.

现在运行:

> sudo pm2 start process.yml

检查pm2的更多选项和功能


4

由于这是Laravel特有的问题,所以我想建议Laravel特有的答案。由于您已经在此服务器上使用了cronjobs,因此建议您将shell命令设置为重复的cronjob,以始终验证该工作程序是否正在运行。您可以将shell命令设置为通过服务器上的cron本机运行,也可以使用Laravel控制台内核来管理该命令并添加逻辑,例如检查是否已经有工作进程在运行,如果没有,请继续并开始备份。

根据您需要多长时间运行一次命令,您可以每周一次甚至每分钟一次不频繁地执行此操作。这将使您能够确保工作程序连续运行,而不必向服务器(例如Supervisor)添加任何开销。如果您信任它,则可以授予对诸如supervisor之类的第三方程序包的权限,但是,如果您可以避免依赖它,则可以考虑采用这种方法。

使用此功能执行所需操作的一个示例是使cronjob每小时运行一次。它将在自定义的Laravel控制台命令中按顺序执行以下命令:

\ Artisan :: call('queue:restart');

\ Artisan :: call('queue:work --daemon');

请注意,这适用于Laravel的旧版本(最高5.3),但我尚未在较新的版本上进行测试。


尽管这是一种选择,并且可以工作,但在最坏的情况下,这将导致排队的任务停机一小时。同样,每次cron运行时,它看起来都会创建一个新进程,如果那样的话最终会耗尽内存。
零一

一个小时的停机时间?我只是说这两个artisan命令应该在cronjob中按顺序运行,而不是一个小时。我将更新原始答案以反映这一点。这不会导致内存问题,因为重新启动命令会终止前一个进程。
eResourcesInc

关于潜在的停机时间,我们的服务器出现问题,工匠守护程序工人最终由于未知原因而被杀死,无法存活。主管是确保其在死后复活的唯一方法。
零一

上面的代码也应该起作用。您可以根据需要多次,每分钟一次地调用这些命令。因此,我不理解有关使用此方法停机一个小时的评论。您可以控制检查和重新启动守护程序的频率。发布此内容的全部目的只是为了举例说明如何仅使用Laravel进行操作。肯定还有其他方法可以做到这一点。但是这种方式不依赖于要安装的外部软件包。
eResourcesInc

1
我认为大多数人不介意安装过程监视器,但是其他人可能不想授予他们无法控制的外部程序包访问权限。这是个人喜好。如果您不介意在服务器上进行这种安装,则服务监视器可能会更干净,但是此方法无需任何其他外部依赖项即可实现相同的效果,并且应与平台无关。但是两者都有优点和缺点。
eResourcesInc

4

最好的方法是PM2(Node.js的高级生产过程管理器),您可以监控队列并查看其日志。

在项目目录中使用以下命令,运行queue worker:

pm2 start artisan --name laravel-worker --interpreter php -- queue:work --daemon


1

您可以使用监控工具。它非常小,对于任何类型的过程管理和监视都非常有用。

从此链接下载二进制程序包后,可以将其解压缩到系统上的文件夹中,然后将两个文件从该程序包复制到系统中以进行安装:

cd /path/to/monit/folder
cp ./bin/monit /usr/sbin/monit
cp ./conf/monitrc /etc/monitrc  

现在,/etc/monitrc根据您的需要进行编辑(参考文档)。然后创建一个初始化控制文件以在启动时启用监视功能。现在开始这样监视:

initctl reload-configuration
start monit

1

对于CentOS7

yum install supervisor

然后在/etc/supervisord.d/filename.ini中创建一个包含内容的文件

[program:laravel-worker]
command=/usr/bin/php /home/appuser/public_html/artisan queue:listen
process_name=%(program_name)s_%(process_num)02d
numprocs=5
priority=999
autostart=true
autorestart=true
startsecs=1
startretries=3
user=appuser
redirect_stderr=true
stdout_logfile=/path/logpath/artisan.log

然后使用以下命令启动监督服务

systemctl restart supervisord

启用监督服务以使用以下命令在启动时运行

systemctl enable supervisord

使用以下命令检查服务是否正在运行

ps aux | grep artisan

如果设置正确,您应该看到该进程正在运行。与下面的输出类似。

[root@server ~]# ps aux | grep artisan
appuser 17444  0.1  0.8 378656 31068 ?        S    12:43   0:05 /usr/bin/php /home/appuser/public_html/artisan queue:listen

1

对于具有systemd作为初始化服务的系统,您可以使用以下服务,使其适应您的项目(在/etc/systemd/system/queue-handler.service上创建):

[Unit]
Description = Queue Handler - Project
After = network-online.target, mysql.service

[Service]
User = www-data
Type = simple
WorkingDirectory=/var/www/project
ExecStart = /usr/bin/php /var/www/project/artisan queue:work --tries=3
Restart = on-failure
RestartSec=5s
RestartPreventExitStatus = 255

[Install]
WantedBy = multi-user.target

重新加载配置并在启动时启用它:

$ systemctl enable queue-handler.service
$ systemctl daemon-reload


0

我没有任何服务监控器或第三方软件就获得了结果。该解决方案工作正常,但我不确定这是否是最佳方法。

只需在函数中以以下方式运行cli命令即可。

use Illuminate\Console\Command;

public function callQueue()
{
        $restart = 'php-cli ' . base_path() . '/artisan queue:restart > /dev/null & echo $!'; 
        $work = 'php-cli ' . base_path() . '/artisan queue:work --timeout=0 --sleep=5 --tries=3 > /dev/null & echo $!';
        exec($restart);
        exec($work);
}

$job = (new jobName())->delay(Carbon::now()->addSeconds(5));
dispatch($job);

原因

我使用这两个命令的原因是,$restart根据该答案中的注释,与之关联的命令可防止出现任何内存问题, 并且与之关联的命令$work可确保该命令在作业之前已成功执行。


-1

我只是使用php artisan queue:work --tries=3 &了让进程在后台运行。但是有时会停止。我不知道为什么会这样

编辑

我通过使用主管解决了这个问题。放置一个运行该php脚本的主管脚本,该脚本将在每次服务器运行时运行


它停止,因为您的服务器有时会重新引导。
Antiomic
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.