92

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

当我 ssh 进入我的服务器并运行 php artisan queue:listen 时,系统工作,但如果我关闭我的终端,监听器将关闭,作业堆积起来并排在队列中,直到我 ssh 重新进入并再次运行监听。

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

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

4

19 回答 19

142

跑步

nohup php artisan queue:work --daemon &

注销时会阻止命令退出。

尾随的与号 (&) 会导致进程在后台启动,因此您可以继续使用 shell 而不必等到脚本完成。

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这样的东西来确保服务保持运行并在崩溃/故障后重新启动。

于 2015-02-20T09:44:09.907 回答
45

你应该使用 linux主管

安装很简单,在 Ubuntu 上我可以使用以下命令安装它:

apt-get install supervisor

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 也将重新启动侦听器。

于 2017-06-12T14:15:21.533 回答
20

命令

nohup php artisan queue:work --daemon &

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

我最终切换到了 Supervisord,这可以像安装在 Ubuntu 上一样简单

sudo apt-get install supervisor 

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

在 AWS AMI Linux 服务器上设置 Supervisord

于 2016-12-15T18:22:43.537 回答
17

来自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;
    }
}
于 2017-08-09T05:43:36.700 回答
16

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

运行此命令时获取输出队列工作者:添加的进程组

其他命令

1)sudo supervisorctl reload

运行此命令时获取输出重新启动的supervisord

2)sudo service supervisor restart

于 2019-08-05T06:17:10.847 回答
8

安装主管

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 步:启动主管:运行以下命令

sudo supervisorctl reread

sudo supervisorctl update

sudo supervisorctl start all

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

额外有用的信息:

  • 停止所有 supervisorctl 进程: 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

于 2019-10-26T04:54:29.503 回答
7

对于那些已经在他们的生产环境中运行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,这个过程只使用内联 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
于 2018-01-09T02:43:12.447 回答
7

使用 pm2

我使用pm2 (高级,Node.js 的生产流程管理器)运行 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 的更多选项和功能

于 2018-03-22T22:19:55.490 回答
6

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

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

pm2 start artisan --name laravel-worker --interpreter php -- queue:work --daemon
于 2019-02-02T11:57:14.457 回答
6

对于使用systemd作为 init 服务的系统,您可以使用以下服务,使其适应您的项目(在 /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
于 2020-06-26T06:48:04.130 回答
4

由于这是一个特定于 Laravel 的问题,我想我会建议一个特定于 Lravel 的答案。由于您已经在此服务器上使用了 cronjobs,因此我建议您将 shell 命令设置为重复的 cronjob,以始终验证 worker 是否正在运行。您可以将 shell 命令设置为通过服务器上的 cron 本地运行,或者您可以使用 Laravel 控制台内核来管理命令并添加逻辑,例如检查您是否已经有一个工作人员正在运行,如果没有,请继续并重新启动它。

根据您需要运行命令的频率,您可以不频繁地执行此操作,每周一次,甚至每分钟一次。这将使您能够确保您的工作人员持续运行,而不必为您的服务器(例如 Supervisor)增加任何开销。如果您信任它,则授予像 supervisor 这样的 3rd 方包的权限是可以的,但如果您可以避免依赖它,您可能需要考虑这种方法。

使用它来做你想做的事情的一个例子是有一个每小时运行的 cronjob。它将在自定义 Laravel 控制台命令中按顺序执行以下操作:

\Artisan::call('队列:重启');

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

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

于 2018-08-20T16:07:47.810 回答
2

如果您开始在屏幕内收听会怎样?请参阅此处:http ://aperiodic.net/screen/quick_reference 然后,即使您注销,屏幕仍将处于活动状态并正在运行。不知道为什么守护进程不起作用。

于 2015-02-20T09:43:34.093 回答
1

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

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

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

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

initctl reload-configuration
start monit
于 2017-10-17T17:57:54.937 回答
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

然后使用启动supervisord服务

systemctl restart supervisord

使 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
于 2019-11-20T08:16:13.973 回答
0

您还可以使用 Docker 容器。

查看:

于 2020-05-27T11:37:48.533 回答
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

于 2020-11-06T11:09:58.457 回答
0

在 Ubuntu 上使用 AWS SQS 连接

安装主管

sudo apt-get install supervisor

配置主管

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

cd /etc/supervisor/conf.d

第 2 步:创建一个工作文件 laravel-worker.conf 来监听队列

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=/opt/bitnami/php/bin/php /opt/bitnami/nginx/html/website/queue:work sqs
autostart=true
autorestart=true
user=root
numprocs=2
redirect_stderr=true
startsecs=0
stdout_logfile=/opt/bitnami/nginx/html/website/storage/logs/supervisord.log

4)sudo supervisorctl reread

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

5)sudo supervisorctl update

运行此命令时获取输出队列工作者:添加的进程组

其他命令

1)sudo supervisorctl reload

运行此命令时获取输出重新启动的supervisord

2)sudo service supervisor restart

3)sudo supervisorctl status

查看进程的状态

于 2022-01-06T15:20:56.910 回答
-1

您可以运行命令行:

php artisan queue:listen --queue=queue_name --tries=1 --memory=128 --timeout=300 >>  storage/logs/queue_log.log &

检查进程运行:

ps aux | grep php
于 2021-06-25T06:49:16.553 回答
-2

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

编辑

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

于 2018-12-21T08:07:06.503 回答