Unetway

Laravel - Queues

Вступление

Laravel теперь предлагает Horizon, красивую панель инструментов и систему конфигурации для ваших очередей с питанием от Redis. Ознакомьтесь с полной документацией Horizon для получения дополнительной информации.

Очереди Laravel предоставляют унифицированный API для различных серверных частей, таких как Beanstalk, Amazon SQS, Redis или даже реляционная база данных. Очереди позволяют отложить обработку трудоемкой задачи, такой как отправка электронной почты, до более позднего времени. Откладывание этих трудоемких задач значительно ускоряет веб-запросы к вашему приложению.

Файл конфигурации очереди хранится в . В этом файле вы найдете конфигурации подключения для каждого из драйверов очереди, которые включены в платформу, которая включает в себя базу данных, Beanstalkd , Amazon SQS , Redis и синхронный драйвер, который будет выполнять задания немедленно (для локального использования). Водитель очереди также включен , который удаляет из очереди заданий.config/queue.phpnull

 

Соединения Vs. Очереди

Прежде чем начать работу с очередями Laravel, важно понять различие между «соединениями» и «очередями». В вашем файле конфигурации есть опция конфигурации. Этот параметр определяет конкретное соединение с серверной службой, такой как Amazon SQS, Beanstalk или Redis. Однако любое заданное соединение с очередью может иметь несколько «очередей», которые могут рассматриваться как разные стеки или группы заданий в очереди.config/queue.phpconnections

Обратите внимание, что каждый пример конфигурации соединения в queueфайле конфигурации содержит queueатрибут. Это очередь по умолчанию, в которую будут отправляться задания при отправке в данное соединение. Другими словами, если вы отправляете задание без явного определения, в какую очередь оно должно быть отправлено, задание будет помещено в очередь, определенную в queueатрибуте конфигурации соединения:

// This job is sent to the default queue...
Job::dispatch();

// This job is sent to the "emails" queue...
Job::dispatch()->onQueue('emails');

Некоторым приложениям может не потребоваться помещать задания в несколько очередей, вместо этого они предпочитают иметь одну простую очередь. Однако отправка заданий в несколько очередей может быть особенно полезна для приложений, которые хотят расставить приоритеты или сегментировать процесс обработки заданий, поскольку работник очереди Laravel позволяет указать, какие очереди следует обрабатывать по приоритету. Например, если вы помещаете задания в highочередь, вы можете запустить работника, который дает им более высокий приоритет обработки:

php artisan queue:work --queue=high,default

 

Примечания и предпосылки для водителя

База данных

Чтобы использовать databaseдрайвер очереди, вам понадобится таблица базы данных для хранения заданий. Чтобы сгенерировать миграцию, создающую эту таблицу, выполните команду Artisan. После того, как миграция была создана, вы можете перенести вашу базу данных с помощью команды:queue:tablemigrate

php artisan queue:table

php artisan migrate

Redis

Чтобы использовать redisдрайвер очереди, вы должны настроить соединение с базой данных Redis в вашем файле конфигурации.config/database.php

Redis Cluster

Если ваше подключение к очереди Redis использует кластер Redis, имена очереди должны содержать ключевой хэш-тег . Это необходимо для того, чтобы все ключи Redis для данной очереди были помещены в один и тот же хэш-слот:

'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => '{default}',
    'retry_after' => 90,
],

блокировка

При использовании очереди Redis вы можете использовать block_forопцию конфигурации, чтобы указать, как долго драйвер должен ждать, пока задание станет доступным, прежде чем выполнять итерацию рабочего цикла и повторный опрос базы данных Redis.

Регулировка этого значения в зависимости от загрузки очереди может быть более эффективной, чем постоянный опрос базы данных Redis на наличие новых заданий. Например, вы можете установить значение, чтобы 5указать, что драйвер должен блокироваться в течение пяти секунд, ожидая, пока задание станет доступным:

'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => 'default',
    'retry_after' => 90,
    'block_for' => 5,
],

Другие условия для водителя

Для перечисленных драйверов очереди необходимы следующие зависимости:

  • Amazon SQS: aws/aws-sdk-php ~3.0
  • Beanstalkd: pda/pheanstalk ~4.0
  • Redis: predis/predis ~1.0

 

Создание рабочих мест

Генерация рабочих классов

По умолчанию все очереди задач для вашего приложения хранятся в каталоге. Если каталог не существует, он будет создан при запуске команды Artisan. Вы можете создать новое задание в очереди с помощью Artisan CLI:app/Jobsapp/Jobsmake:job

php artisan make:job ProcessPodcast

Сгенерированный класс будет реализовывать интерфейс, указывающий Laravel, что задание должно быть помещено в очередь для асинхронного запуска.Illuminate\Contracts\Queue\ShouldQueue

 

Структура класса

Классы заданий очень просты, обычно содержат только handleметод, который вызывается, когда задание обрабатывается в очереди. Для начала давайте рассмотрим пример класса работы. В этом примере мы представим, что управляем службой публикации подкастов и должны обработать загруженные файлы подкастов перед их публикацией:

<?php

namespace App\Jobs;

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

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

    protected $podcast;

    /**
     * Create a new job instance.
     *
     * @param  Podcast  $podcast
     * @return void
     */
    public function __construct(Podcast $podcast)
    {
        $this->podcast = $podcast;
    }

    /**
     * Execute the job.
     *
     * @param  AudioProcessor  $processor
     * @return void
     */
    public function handle(AudioProcessor $processor)
    {
        // Process uploaded podcast...
    }
}

В этом примере обратите внимание, что мы смогли передать модель Eloquent непосредственно в конструктор заданий в очереди. Из-за SerializesModelsособенностей, которые использует задание, модели Eloquent будут изящно сериализованы и не сериализованы при обработке задания. Если ваше задание в очереди принимает модель Eloquent в своем конструкторе, только идентификатор модели будет сериализован в очередь. Когда задание действительно обработано, система очередей автоматически повторно извлечет полный экземпляр модели из базы данных. Все это полностью прозрачно для вашего приложения и предотвращает проблемы, которые могут возникнуть при сериализации полных экземпляров модели Eloquent.

handleМетод вызывается , когда задание обрабатывается очереди. Обратите внимание, что мы можем указать зависимости подсказки от handleметода задания. Сервисный контейнер Laravel автоматически внедряет эти зависимости.

Если вы хотите получить полный контроль над тем, как контейнер внедряет зависимости в handleметод, вы можете использовать метод контейнера bindMethodbindMethodМетод принимает функцию обратного вызова , который принимает работу и контейнер. Внутри обратного вызова вы можете вызывать handleметод по своему усмотрению. Как правило, вы должны вызывать этот метод у поставщика услуг :

use App\Jobs\ProcessPodcast;

$this->app->bindMethod(ProcessPodcast::class.'@handle', function ($job, $app) {
    return $job->handle($app->make(AudioProcessor::class));
});

Двоичные данные, такие как необработанное содержимое изображения, должны быть переданы через base64_encodeфункцию перед передачей в очередь. В противном случае задание может неправильно сериализоваться в JSON при помещении в очередь.

 

Диспетчерские вакансии

После того, как вы написали свой класс работы, вы можете отправить его, используя dispatchметод самой работы. Аргументы, переданные dispatchметоду, будут переданы конструктору задания:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Create podcast...

        ProcessPodcast::dispatch($podcast);
    }
}

 

Задержка отправки

Если вы хотите отложить выполнение задания из очереди, вы можете использовать этот delayметод при отправке задания. Например, давайте укажем, что задание не должно быть доступно для обработки до 10 минут после отправки:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Create podcast...

        ProcessPodcast::dispatch($podcast)
                ->delay(now()->addMinutes(10));
    }
}

Служба очереди Amazon SQS имеет максимальное время задержки 15 минут.

 

Синхронная диспетчеризация

Если вы хотите отправить задание немедленно (синхронно), вы можете использовать этот dispatchNowметод. При использовании этого метода задание не будет поставлено в очередь и будет немедленно запущено в текущем процессе:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Jobs\ProcessPodcast;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Create podcast...

        ProcessPodcast::dispatchNow($podcast);
    }
}

 

Цепочка вакансий

Цепочка заданий позволяет вам указать список заданий в очереди, которые должны выполняться последовательно. В случае сбоя одного задания в последовательности остальные задания не будут выполнены. Чтобы выполнить цепочку заданий, поставленных в очередь, вы можете использовать withChainметод для любого из ваших диспетчеризуемых заданий:

ProcessPodcast::withChain([
    new OptimizePodcast,
    new ReleasePodcast
])->dispatch();

Удаление заданий с использованием этого метода не помешает выполнению связанных заданий. Цепочка прекратит выполнение только в случае сбоя задания в цепочке.$this->delete()

Цепное соединение и очередь

Если вы хотите , чтобы указать соединение по умолчанию и очередь , которая должна быть использована для прикованных заданий, вы можете использовать allOnConnectionи allOnQueueметоду. Эти методы указывают соединение с очередью и имя очереди, которые следует использовать, если заданию в очереди явно не назначено другое соединение / очередь:

ProcessPodcast::withChain([
    new OptimizePodcast,
    new ReleasePodcast
])->dispatch()->allOnConnection('redis')->allOnQueue('podcasts');

 

Настройка очереди и соединения

Отправка в определенную очередь

Перемещая задания в разные очереди, вы можете «классифицировать» задания, поставленные в очередь, и даже расставить приоритеты по количеству работников, назначенных для разных очередей. Имейте в виду, что это не подталкивает задания к различным «соединениям» очереди, как определено вашим файлом конфигурации очереди, а только к определенным очередям в пределах одного соединения. Чтобы указать очередь, используйте onQueueметод при отправке задания:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Create podcast...

        ProcessPodcast::dispatch($podcast)->onQueue('processing');
    }
}

Отправление к определенному соединению

Если вы работаете с несколькими подключениями к очереди, вы можете указать, к какому соединению следует добавить задание. Чтобы указать соединение, используйте onConnectionметод при отправке задания:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Create podcast...

        ProcessPodcast::dispatch($podcast)->onConnection('sqs');
    }
}

Вы можете приковать onConnectionи onQueueметоды для определения соединения и очереди на работу:

ProcessPodcast::dispatch($podcast)
              ->onConnection('sqs')
              ->onQueue('processing');

В качестве альтернативы вы можете указать connectionкак свойство в классе задания:

<?php

namespace App\Jobs;

class ProcessPodcast implements ShouldQueue
{
    /**
     * The queue connection that should handle the job.
     *
     * @var string
     */
    public $connection = 'sqs';
}

 

Задание максимальных попыток задания / значений тайм-аута

Макс Попытки

Один из подходов к определению максимального количества попыток выполнения задания - через --triesпереключатель в командной строке Artisan:

php artisan queue:work --tries=3

Однако вы можете выбрать более детальный подход, определив максимальное количество попыток для самого класса заданий. Если в задании указано максимальное количество попыток, оно будет иметь приоритет над значением, указанным в командной строке:

<?php

namespace App\Jobs;

class ProcessPodcast implements ShouldQueue
{
    /**
     * The number of times the job may be attempted.
     *
     * @var int
     */
    public $tries = 5;
}

 

Попытки, основанные на времени

В качестве альтернативы определению того, сколько раз может быть выполнено задание до его сбоя, вы можете указать время, в течение которого задание должно прерваться. Это позволяет выполнить задание любое количество раз в течение определенного периода времени. Чтобы определить время, в которое задание должно истечь, добавьте retryUntilметод в свой класс задания:

/**
 * Determine the time at which the job should timeout.
 *
 * @return \DateTime
 */
public function retryUntil()
{
    return now()->addSeconds(5);
}

Вы также можете определить retryUntilметод для своих слушателей событий в очереди.

Тайм-аут

timeoutФункция оптимизирована для PHP 7.1+ и pcntlрасширение PHP.

Аналогично, максимальное количество секунд, которое могут выполняться задания, может быть указано с помощью --timeoutпереключателя в командной строке Artisan:

php artisan queue:work --timeout=30

Однако вы также можете определить максимальное количество секунд, которое должно быть разрешено заданию для самого класса задания. Если для задания указано время ожидания, оно будет иметь приоритет над любым временем ожидания, указанным в командной строке:

<?php

namespace App\Jobs;

class ProcessPodcast implements ShouldQueue
{
    /**
     * The number of seconds the job can run before timing out.
     *
     * @var int
     */
    public $timeout = 120;
}

 

Ограничение скорости

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

Если ваше приложение взаимодействует с Redis, вы можете ограничить количество заданий в очереди по времени или параллелизму. Эта функция может быть полезна, когда ваши задания в очереди взаимодействуют с API, которые также ограничены по скорости.

Например, используя throttleметод, вы можете ограничить задание определенного типа, чтобы оно выполнялось только 10 раз каждые 60 секунд. Если блокировка не может быть получена, вы обычно должны вернуть задание обратно в очередь, чтобы его можно было повторить позже:

Redis::throttle('key')->allow(10)->every(60)->then(function () {
    // Job logic...
}, function () {
    // Could not obtain lock...

    return $this->release(10);
});

В приведенном выше примере, keyможет быть любая строка, которая однозначно определяет тип задания, которое вы хотели бы ограничить. Например, вы можете создать ключ на основе имени класса задания и идентификаторов моделей Eloquent, с которыми оно работает.

Выпуск задушенного задания обратно в очередь по-прежнему увеличивает общее число заданий attempts.

Кроме того, вы можете указать максимальное количество работников, которые могут одновременно обрабатывать задание. Это может быть полезно, когда задание в очереди изменяет ресурс, который должен изменяться только одним заданием за раз. Например, используя funnelметод, вы можете ограничить выполнение заданий определенного типа только одним рабочим за раз:

Redis::funnel('key')->limit(1)->then(function () {
    // Job logic...
}, function () {
    // Could not obtain lock...

    return $this->release(10);
});

При использовании ограничения скорости может быть трудно определить количество попыток, необходимых для успешного выполнения вашей работы. Поэтому полезно сочетать ограничение скорости с попытками, основанными на времени .

 

Обработка ошибок

Если во время обработки задания возникает исключение, задание будет автоматически возвращено в очередь, поэтому его можно повторить. Задание будет продолжать освобождаться до тех пор, пока не будет предпринято максимальное количество попыток, допустимое вашим приложением. Максимальное количество попыток определяется --triesпереключателем, используемым в команде Artisan. В качестве альтернативы, максимальное количество попыток может быть определено в самом классе задания. Более подробную информацию о запуске работника очереди можно найти ниже .queue:work

 

Закрытие очереди

Вместо отправки класса задания в очередь, вы также можете отправить замыкание. Это отлично подходит для быстрых, простых задач, которые должны быть выполнены вне текущего цикла запроса:

$podcast = App\Podcast::find(1);

dispatch(function () use ($podcast) {
    $podcast->publish();
});

При отправке Closures в очередь содержимое кода Closure криптографически подписывается, поэтому его нельзя изменить при передаче.

 

Запуск работника очереди

Laravel включает в себя работника очереди, который будет обрабатывать новые задания по мере их поступления в очередь. Вы можете запустить работника, используя команду Artisan. Обратите внимание, что после запуска команды она будет продолжаться до тех пор, пока она не будет остановлена ​​вручную или вы не закроете свой терминал:queue:workqueue:work

php artisan queue:work

Чтобы процесс работал постоянно в фоновом режиме, вы должны использовать монитор процесса, такой как Supervisor, чтобы гарантировать, что работник очереди не перестанет работать.queue:work

Помните, что работники очереди являются долгоживущими процессами и хранят загруженное состояние приложения в памяти. В результате они не заметят изменений в вашей кодовой базе после их запуска. Поэтому во время процесса развертывания обязательно перезапустите работников очереди .

Указание соединения и очереди

Вы также можете указать, какое подключение к очереди должен использовать работник. Имя соединения, переданное workкоманде, должно соответствовать одному из соединений, определенных в вашем файле конфигурации:config/queue.php

php artisan queue:work redis

Вы можете еще больше настроить своего работника очереди, обрабатывая только определенные очереди для данного соединения. Например, если все ваши электронные письма обрабатываются в emailsочереди в вашем redisподключении к очереди, вы можете выполнить следующую команду, чтобы запустить работника, который обрабатывает только эту очередь:

php artisan queue:work redis --queue=emails

Обработка одного задания

--onceВариант может быть использован , чтобы поручить работнику обрабатывать только одно задание из очереди:

php artisan queue:work --once

Обработка всех заданий в очереди и выход

Эта опция может использоваться, чтобы проинструктировать работника обрабатывать все задания и затем корректно завершать работу. Эта опция может быть полезна при работе с очередями Laravel в контейнере Docker, если вы хотите закрыть контейнер после того, как очередь пуста:--stop-when-empty

php artisan queue:work --stop-when-empty

Ресурсы

Работники очереди демонов не «перезагружают» каркас перед обработкой каждого задания. Поэтому вы должны освобождать любые тяжелые ресурсы после завершения каждой работы. Например, если вы выполняете манипуляции с изображениями с помощью библиотеки GD, вы должны освободить память, imagedestroyкогда закончите.

Приоритеты очереди

Иногда вы можете расставить приоритеты в обработке ваших очередей. Например, в вашем вы можете установить по умолчанию для вашего подключения к . Однако иногда вы можете отправить задание в приоритетную очередь следующим образом:config/queue.phpqueueredislowhigh

dispatch((new Job)->onQueue('high'));

Чтобы запустить работника, который проверяет, что все highзадания очереди обрабатываются, прежде чем lowпереходить к каким-либо заданиям в очереди, передайте в workкоманду список имен очередей, разделенных запятыми :

php artisan queue:work --queue=high,low

 

Рабочие очереди и развертывание

Поскольку работники очереди являются долгоживущими процессами, они не получат изменения в вашем коде без перезапуска. Итак, самый простой способ развертывания приложения с использованием работников очереди - это перезапустить работников во время процесса развертывания. Вы можете корректно перезапустить всех рабочих, выполнив команду:queue:restart

php artisan queue:restart

Эта команда будет указывать всем работникам очереди изящно «умереть» после того, как они завершат обработку своего текущего задания, так что ни одно из существующих заданий не будет потеряно. Поскольку работники очереди умрут при выполнении команды, вы должны запустить диспетчер процессов, такой как Supervisor, для автоматического перезапуска работников очереди.queue:restart

Очередь использует кэш для хранения сигналов перезапуска, поэтому перед использованием этой функции необходимо убедиться, что драйвер кеша правильно настроен для вашего приложения.

 

Истечение срока работы и тайм-ауты

Срок действия

В вашем файле конфигурации каждое подключение очереди определяет опцию. Этот параметр указывает, сколько секунд соединение очереди должно ждать, прежде чем повторять работу, которая обрабатывается. Например, если значение установлено в , задание будет возвращено в очередь, если оно обрабатывалось в течение 90 секунд без удаления. Как правило, вы должны установить максимальное количество секунд, в течение которых ваши задания должны разумно занять время для завершения обработки.config/queue.phpretry_afterretry_after90retry_after

Единственное подключение к очереди, которое не содержит retry_afterзначения, - это Amazon SQS. SQS повторит задание в соответствии с Тайм-аутом видимости по умолчанию, который управляется в консоли AWS.

Тайм-аут работников

Команда Artisan предоставляет возможность выбора. Параметр определяет , как долго главный процесс очереди Laravel будет ждать , прежде чем убивать ребенок - очередь работника , который обрабатывает задание. Иногда дочерний процесс очереди может зависнуть по разным причинам, например, внешний HTTP-вызов не отвечает. Опция удаляет замороженные процессы, превысившие , что указанный срок:queue:work--timeout--timeout--timeout

php artisan queue:work --timeout=60

Параметр retry_afterконфигурации и параметр --timeoutCLI различны, но работают вместе, чтобы гарантировать, что задания не будут потеряны и что задания будут успешно обработаны только один раз.

--timeoutЗначение всегда должно быть по крайней мере на несколько секунд короче , чем retry_afterзначение конфигурации. Это гарантирует, что работник, обрабатывающий заданное задание, всегда будет убит до повторного выполнения задания. Если ваш --timeoutвариант длиннее значения вашей retry_afterконфигурации, ваши задания могут быть обработаны дважды.

Продолжительность сна работника

Когда задания будут доступны в очереди, работник продолжит обрабатывать задания без задержки между ними. Однако эта sleepопция определяет, как долго (в секундах) работник будет «спать», если новых рабочих мест не будет. Во время сна работник не будет обрабатывать новые задания - задания будут обрабатываться после того, как работник снова проснется.

php artisan queue:work --sleep=3

 

Конфигурация супервизора

Установка Supervisor

Supervisor - это монитор процессов для операционной системы Linux, который автоматически перезапустит ваш процесс в случае сбоя. Чтобы установить Supervisor в Ubuntu, вы можете использовать следующую команду:queue:work

sudo apt-get install supervisor

Если настройка Supervisor сама по себе кажется излишней, подумайте об использовании Laravel Forge , который автоматически установит и настроит Supervisor для ваших проектов Laravel.

Настройка супервизора

Файлы конфигурации супервизора обычно хранятся в каталоге. В этом каталоге вы можете создать любое количество файлов конфигурации, которые инструктируют супервизора, как следует отслеживать ваши процессы. Например, давайте создадим файл, который запускает и контролирует процесс:/etc/supervisor/conf.dlaravel-worker.confqueue:work

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3
autostart=true
autorestart=true
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/home/forge/app.com/worker.log

В этом примере numprocsдиректива будет инструктировать Supervisor запускать 8 процессов и отслеживать все из них, автоматически перезапуская их в случае сбоя. Вы должны изменить часть директивы, чтобы отразить желаемое соединение с очередью.queue:workqueue:work sqscommand

Начальный руководитель

После того, как файл конфигурации был создан, вы можете обновить конфигурацию Supervisor и запустить процессы, используя следующие команды:

sudo supervisorctl reread

sudo supervisorctl update

sudo supervisorctl start laravel-worker:*

Для получения дополнительной информации о супервизоре, обратитесь к документации супервизора .

 

Работа с ошибочными рабочими местами

Иногда ваша работа в очереди не удастся. Не волнуйтесь, все не всегда идет как запланировано! В Laravel есть удобный способ указать максимальное количество попыток выполнения задания. После того, как задание превысило это количество попыток, оно будет вставлено в failed_jobsтаблицу базы данных. Чтобы создать миграцию для failed_jobsтаблицы, вы можете использовать команду:queue:failed-table

php artisan queue:failed-table

php artisan migrate

Затем, когда вы запускаете работника очереди , вы должны указать максимальное количество попыток выполнения задания с помощью --triesпереключателя в команде. Если вы не укажете значение для опции, задания будут выполняться бесконечно:queue:work--tries

php artisan queue:work redis --tries=3

Кроме того, вы можете указать, сколько секунд Laravel должен подождать, прежде чем повторять попытку задания, которое не удалось, используя эту --delayопцию. По умолчанию задание повторяется немедленно:

php artisan queue:work redis --tries=3 --delay=3

Если вы хотите настроить задержку повторения неудачного задания для каждого отдельного задания, вы можете сделать это, определив retryAfterсвойство для вашего класса заданий в очереди:

/**
 * The number of seconds to wait before retrying the job.
 *
 * @var int
 */
public $retryAfter = 3;

 

Очистка после неудачных работ

Вы можете определить failedметод непосредственно в своем классе заданий, позволяющий выполнять очистку для конкретного задания в случае сбоя. Это идеальное место для отправки оповещения вашим пользователям или отмены любых действий, выполненных заданием. То, Exceptionчто вызвало сбой задания, будет передано failedметоду:

<?php

namespace App\Jobs;

use Exception;
use App\Podcast;
use App\AudioProcessor;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessPodcast implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    protected $podcast;

    /**
     * Create a new job instance.
     *
     * @param  Podcast  $podcast
     * @return void
     */
    public function __construct(Podcast $podcast)
    {
        $this->podcast = $podcast;
    }

    /**
     * Execute the job.
     *
     * @param  AudioProcessor  $processor
     * @return void
     */
    public function handle(AudioProcessor $processor)
    {
        // Process uploaded podcast...
    }

    /**
     * The job failed to process.
     *
     * @param  Exception  $exception
     * @return void
     */
    public function failed(Exception $exception)
    {
        // Send user notification of failure, etc...
    }
}

 

Неудачные вакансии

Если вы хотите зарегистрировать событие, которое будет вызываться при сбое задания, вы можете использовать этот метод. Это событие - отличная возможность уведомить вашу команду по электронной почте или Slack . Например, мы можем прикрепить обратный вызов к этому событию из того, что включено в Laravel:Queue::failingAppServiceProvider

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Queue;
use Illuminate\Queue\Events\JobFailed;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Queue::failing(function (JobFailed $event) {
            // $event->connectionName
            // $event->job
            // $event->exception
        });
    }
}

 

Повторная попытка неудачных заданий

Чтобы просмотреть все невыполненные задания, которые были вставлены в failed_jobsтаблицу базы данных, вы можете использовать команду Artisan:queue:failed

php artisan queue:failed

Команда выведет список идентификатора задания, соединения, очереди и времени отказа. Идентификатор задания можно использовать, чтобы повторить сбойное задание. Например, чтобы повторить неудачное задание с идентификатором , введите следующую команду:queue:failed5

php artisan queue:retry 5

Чтобы повторить все неудачные задания, выполните команду и передайте в качестве идентификатора:queue:retryall

php artisan queue:retry all

Если вы хотите удалить невыполненную работу, вы можете использовать команду:queue:forget

php artisan queue:forget 5

Чтобы удалить все неудачные задания, вы можете использовать команду:queue:flush

php artisan queue:flush

 

Игнорирование недостающих моделей

При внедрении модели Eloquent в задание она автоматически сериализуется перед помещением в очередь и восстанавливается при обработке задания. Однако, если модель была удалена, когда задание ожидало обработки работником, ваша работа может завершиться ошибкой с ModelNotFoundException.

Для удобства вы можете выбрать автоматическое удаление заданий с отсутствующими моделями, установив для deleteWhenMissingModelsсвойства задания следующее true:

/**
 * Delete the job if its models no longer exist.
 *
 * @var bool
 */
public $deleteWhenMissingModels = true;

 

Работа события

Использование beforeи afterметод на Queue фасаде , вы можете указать функции обратного вызова , которые должны выполняться до или после постановки задания в очереди обрабатывается. Эти обратные вызовы являются отличной возможностью для дополнительной регистрации или увеличения статистики для панели мониторинга. Как правило, вы должны вызывать эти методы у поставщика услуг . Например, мы можем использовать то, AppServiceProviderчто включено в Laravel:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Queue;
use Illuminate\Support\ServiceProvider;
use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobProcessing;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Queue::before(function (JobProcessing $event) {
            // $event->connectionName
            // $event->job
            // $event->job->payload()
        });

        Queue::after(function (JobProcessed $event) {
            // $event->connectionName
            // $event->job
            // $event->job->payload()
        });
    }
}

Используя loopingметод на Queue фасаде , вы можете указать обратные вызовы, которые выполняются до того, как работник попытается получить задание из очереди. Например, вы можете зарегистрировать Closure, чтобы откатить любые транзакции, которые были оставлены открытыми ранее неудачным заданием:

Queue::looping(function () {
    while (DB::transactionLevel() > 0) {
        DB::rollBack();
    }
});