Очередь Laravel с супервизором, не работающая с несколькими веб-сайтами

#laravel #supervisord

#laravel #супервизор

Вопрос:

При добавлении одного веб-сайта, на котором выполняется очередь Laravel, в Supervisor отложенные задания обрабатываются должным образом.

Когда я добавляю другой веб-сайт в супервизор, отложенные задания не обрабатываются ни для одного из веб-сайтов / очередей.

Я попытался перечитать, перезагрузить и перезапустить службу. В supervisord.log отображаются все запущенные процессы, но задания не запускаются.

Если я остановлю всех, кроме 1 рабочего, очередь заработает.

Laravel 5.7

Супервизор 3.3.1

redis-cli 3.2.6

Debian / Nginx

 sudo nano /etc/supervisor/conf.d/website-a-worker.conf
  
 [program:website-a-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/website.a/artisan queue:work redis --sleep=3 --tries=3
autostart=true
autorestart=true
#user=laravel
numprocs=8
autostart=true
autorestart=true
stdout_logfile=/var/www/website.a/storage/logs/worker.log
stderr_logfile=/var/www/website.a/storage/logs/worker.err.log
  
 sudo nano /etc/supervisor/conf.d/website-b-worker.conf
  
 [program:website-b-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/website.b/artisan queue:work redis --sleep=3 --tries=3
autostart=true
autorestart=true
#user=laravel
numprocs=8
autostart=true
autorestart=true
stdout_logfile=/var/www/website.b/storage/logs/worker.log
stderr_logfile=/var/www/website.b/storage/logs/worker.err.log
  
 sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start website-a-worker:*
sudo supervisorctl start website-b-worker:*

  
 // config/queue.php
...
'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => 'default',
            'retry_after' => 600,
            'block_for' => null,
        ],
...
  
 <?php
namespace AppJobs;
use IlluminateBusQueueable;
use IlluminateQueueSerializesModels;
use IlluminateQueueInteractsWithQueue;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;

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

    public function handle()
    {
       Log::info('This only gets triggered if 1 supervisor worker is running.');
    }
}
  
 > sudo service supervisor restart
> cd /var/www/website.a
> php artisan tinker

>>> AppJobsSomeJob::dispatch()->delay(1);
# Job does not get triggered
>>> exit
  

Задание никогда не запускается.
Однако, если я остановлю супервизор для website.b, website.a будет обрабатывать задания.

 > sudo supervisorctl stop website-b-worker:*
website-b-worker:website-b-worker_02: stopped
website-b-worker:website-b-worker_03: stopped
website-b-worker:website-b-worker_00: stopped
website-b-worker:website-b-worker_01: stopped
website-b-worker:website-b-worker_06: stopped
website-b-worker:website-b-worker_07: stopped
website-b-worker:website-b-worker_04: stopped
website-b-worker:website-b-worker_05: stopped

> php artisan tinker

>>> AppJobsSomeJob::dispatch()->delay(1);
# Job gets triggered!

  

Как я могу запустить несколько рабочих (по крайней мере, 1 для каждого веб-сайта)?

Комментарии:

1. Я никогда не пробовал супервизор с несколькими веб-сайтами. Но в порядке ли numprocs значения относительно того, что у вас много веб-сайтов?

2. Смотрите мою правку в ответе, это намного лучше, чем ставить $this->onQueue() на каждое задание и устанавливать имя очереди автоматически в конфигурации очереди: 'queue' => 'websiteAQueue', .

Ответ №1:

Я использовал Supervisor с Laravel и Redis, но только для 1 веб-сайта одновременно. Однако я провел некоторое исследование и обнаружил, что вы можете указать имя процесса очереди в Laravelhttps://laravel.com/docs/5.8/queues#connections-vs-queues .

В Laravel Job есть метод установки onQueue() для указания имени очереди. пример laravel docs :

 Job::dispatch()->onQueue('emails');
  

Но в вашем коде SomeJob вы можете вызвать это напрямую с помощью $this->onQueue('queue_name') ; ваш код может быть похож :

 <?php
namespace AppJobs;
use IlluminateBusQueueable;
use IlluminateQueueSerializesModels;
use IlluminateQueueInteractsWithQueue;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;

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

    public function handle()
    {
        // on website a
        $this->onQueue('websiteAQueue');
        Log::info('This only gets triggered if 1 supervisor worker is running.');
    }
}
  

И в процессе супервизора для веб-сайта A укажите параметр очереди равным websiteAQueue :

 [program:website-a-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/website.a/artisan queue:work redis --queue=WebsiteAQueue --sleep=3 --tries=3
autostart=true
autorestart=true
#user=laravel
numprocs=8
autostart=true
autorestart=true
stdout_logfile=/var/www/website.a/storage/logs/worker.log
stderr_logfile=/var/www/website.a/storage/logs/worker.err.log
  

Таким образом, когда Laravel отправляет задание, оно отправит его в указанную очередь, а не в очередь по умолчанию, которую оно нашло.

Редактировать————————

Или лучше, вы можете использовать другое имя очереди для каждой конфигурации веб-сайта :

 // Website A : config/queue.php
...
'redis' => [
            'driver' => 'redis',
            'connection' => 'default',
            'queue' => 'websiteAQueue',
            'retry_after' => 600,
            'block_for' => null,
        ],
...
  

Таким образом, все очереди отправляются в websiteAQueue автоматически, поэтому вам не нужно использовать $this->onQueue() для каждого задания.

Комментарии:

1. Да, в итоге я использовал второй вариант — редактирование конфигурации / очереди. php и изменение имени очереди для каждого сайта и указание имени очереди в .conf.