Версія фреймворка: 8.x

Черги

Вступ

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

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

Файл конфігурації черги зберігається вconfig/queue.php. У цьому файлі ви знайдете конфігурації підключення для кожного з драйверів черги, що входять до фреймворку, що включає базу даних,Beanstalkd,Amazon SQS,Редіста синхронний драйвер, який негайно виконуватиме завдання (для локального використання). Anullтакож включений драйвер черги, який відкидає завдання, що стоять у черзі.

Зв’язки проти Черги

Перш ніж розпочати роботу з чергами Laravel, важливо зрозуміти різницю між "з'єднаннями" та "чергами". У вашомуconfig/queue.phpфайл конфігурації, є файлconnectionsваріант конфігурації. Цей параметр визначає конкретне підключення до серверної служби, такої як Amazon SQS, Beanstalk або Redis. Однак будь-яке дане підключення до черги може мати кілька "черг", які можна розглядати як різні стеки або купи завдань, що стоять у черзі.

Зверніть увагу, що кожен приклад конфігурації з'єднання в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драйвера черги, вам знадобиться таблиця бази даних для зберігання завдань. Щоб створити міграцію, яка створює цю таблицю, запустітьqueue:tableartisan командування. Після створення міграції ви можете перенести базу даних за допомогоюmigrateкоманда:

php artisan queue:table

php artisan migrate

Редіс

Для того, щоб використовуватиredisдрайвера черги, вам слід налаштувати підключення до бази даних Redis у вашомуconfig/database.phpфайл конфігурації.

Кластер Редіс

Якщо підключення до черги 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,
],
Налаштуванняblock_forдо0призведе до того, що працівники черги блокуватимуть на невизначений час, поки не з’явиться робота. Це також запобіжить такі сигнали, якSIGTERMвід обробки до обробки наступного завдання.

Інші передумови драйвера

Для перелічених драйверів черги потрібні такі залежності:

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

Створення робочих місць

Створення класів робочих місць

За замовчуванням усі завдання, що знаходяться в черзі для вашої програми, зберігаються вapp/Jobsкаталог. Якщоapp/Jobsкаталог не існує, він буде створений під час запускуmake:jobartisan командування. Ви можете створити нову роботу в черзі за допомогою Artisan CLI:

php artisan make:job ProcessPodcast

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

Вакансії можуть бути налаштовані за допомогоюзаглушка видавництва

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

Класи роботи дуже прості, зазвичай містять лише ahandleметод, який викликається, коли завдання обробляється чергою. Для початку давайте розглянемо приклад класу роботи. У цьому прикладі ми зробимо вигляд, що керуємо службою публікації подкастів і потребуємо обробки завантажених файлів подкастів до їх публікації:

<?php

namespace App\Jobs;

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

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...
    }
}

У цьому прикладі зауважте, що нам вдалося передатиКрасномовна модельбезпосередньо в конструкторі завдання, яке знаходиться в черзі. ЧерезSerializesModelsриси, яку використовує робота, красномовні моделі та їх навантажені відносини будуть витончено серіалізовані та несеріалізовані під час обробки завдання. Якщо ваше завдання в черзі приймає модель Eloquent у своєму конструкторі, лише ідентифікатор моделі буде серіалізований в черзі. Коли завдання справді обробляється, система черги автоматично повторно отримує повний екземпляр моделі та її завантажені зв’язки з бази даних. Це все абсолютно прозоро для вашої програми та запобігає проблемам, які можуть виникнути при серіалізації повних екземплярів моделі Eloquent.

handleметод викликається, коли завдання обробляється чергою. Зверніть увагу, що ми можемо вводити залежності натяку наhandleметод роботи. Ларавельслужбовий контейнеравтоматично вводить ці залежності.

Якщо ви хочете взяти повний контроль над тим, як контейнер вводить залежності вhandleметодом, ви можете використовувати контейнерbindMethodметод.bindMethodметод приймає зворотний виклик, який отримує завдання та контейнер. В рамках зворотного виклику ви можете вільно викликатиhandleметод, як завгодно. Як правило, вам слід викликати цей метод ізпостачальник послуг:

use App\Jobs\ProcessPodcast;

$this->app->bindMethod(ProcessPodcast::class.'@handle', function ($job, $app) {
    return $job->handle($app->make(AudioProcessor::class));
});
Двійкові дані, такі як вміст вихідного зображення, повинні передаватися черезbase64_encodeфункція перед передачею на завдання в черзі. В іншому випадку завдання може неправильно серіалізуватися в JSON при розміщенні в черзі.

Обробка відносин

Оскільки завантажені відносини також серіалізуються, серіалізований рядок завдань може стати досить великим. Щоб запобігти серіалізації відносин, ви можете зателефонувати за номеромwithoutRelationsметод на моделі при встановленні значення властивості. Цей метод поверне екземпляр моделі без завантажених зв'язків:

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

Унікальні робочі місця

Унікальні завдання вимагають драйвера кеш-пам’яті, який підтримуєзамки.

Іноді вам може знадобитися переконатися, що в черзі в будь-який момент часу знаходиться лише один екземпляр конкретного завдання. Ви можете зробити це, застосувавшиShouldBeUniqueінтерфейс для вашого робочого класу:

<?php

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;

class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
    ...
}

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

У деяких випадках вам може знадобитися визначити конкретний "ключ", який робить завдання унікальним, або ви можете вказати час очікування, після якого робота більше не залишається унікальною. Для цього ви можете визначитиuniqueIdіuniqueForвластивості або методи у вашому робочому класі:

<?php

use App\Product;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;

class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
    /**
     * The product instance.
     *
     * @var \App\Product
     */
    public $product;

    /**
    * The number of seconds after which the job's unique lock will be released.
    *
    * @var int
    */
    public $uniqueFor = 3600;

    /**
    * The unique ID of the job.
    *
    * @return string
    */
    public function uniqueId()
    {
        return $this->product->id;
    }
}

У наведеному вище прикладіUpdateSearchIndexЗавдання унікальне за ідентифікатором продукту. Отже, будь-які нові відправлення завдання з однаковим ідентифікатором товару будуть ігноруватися, поки не завершиться обробка існуючого завдання. Крім того, якщо існуюче завдання не буде оброблено протягом однієї години, унікальний замок буде звільнений, а інше завдання з тим самим унікальним ключем може бути відправлено в чергу.

Унікальні замки роботи

За лаштунками, коли аShouldBeUniqueробота відправлена, Laravel намагається придбатизамокза допомогоюuniqueIdключ. Якщо замок не отримано, відправка ігнорується. Це блокування звільняється, коли завдання завершує обробку або не вдається виконати всі спроби повторної спроби. За замовчуванням Laravel використовуватиме драйвер кешу за замовчуванням для отримання цього блокування. Однак, якщо ви хочете використовувати інший драйвер для отримання блокування, ви можете визначити auniqueViaметод, який повертає драйвер кешу, який слід використовувати:

use Illuminate\Support\Facades\Cache;

class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
    ...

    /**
    * Get the cache driver for the unique job lock.
    *
    * @return \Illuminate\Contracts\Cache\Repository
    */
    public function uniqueVia()
    {
        return Cache::driver('redis');
    }
}
Якщо потрібно лише обмежити одночасну обробку завдання, використовуйтеWithoutOverlappingзамість цього Middlware.

Робота проміжного програмного забезпечення

Проміжне програмне забезпечення для роботи дозволяє обернути власну логіку навколо виконання завдань, що знаходяться в черзі, зменшуючи шаблон в самих робочих місцях. Наприклад, розглянемо наступнеhandleметод, який використовує функції обмеження швидкості Redis від Laravel, щоб дозволити обробляти лише одне завдання кожні п’ять секунд:

/**
 * Execute the job.
 *
 * @return void
 */
public function handle()
{
    Redis::throttle('key')->block(0)->allow(1)->every(5)->then(function () {
        info('Lock obtained...');

        // Handle job...
    }, function () {
        // Could not obtain lock...

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

Поки цей код дійсний, структураhandleметод стає галасливим, оскільки він захаращений логікою обмеження швидкості Редіса. Крім того, ця логіка обмеження швидкості повинна бути продубльована для будь-яких інших завдань, які ми хочемо встановити.

Замість обмеження швидкості в методі дескриптора ми могли б визначити Middlware, яке обробляє обмеження швидкості. Laravel не має розташування за замовчуванням для проміжного програмного забезпечення, тому ви можете розмістити Middlware для роботи в будь-якому місці програми. У цьому прикладі ми розмістимо Middlware вapp/Jobs/Middlewareкаталог:

<?php

namespace App\Jobs\Middleware;

use Illuminate\Support\Facades\Redis;

class RateLimited
{
    /**
     * Process the queued job.
     *
     * @param  mixed  $job
     * @param  callable  $next
     * @return mixed
     */
    public function handle($job, $next)
    {
        Redis::throttle('key')
                ->block(0)->allow(1)->every(5)
                ->then(function () use ($job, $next) {
                    // Lock obtained...

                    $next($job);
                }, function () use ($job) {
                    // Could not obtain lock...

                    $job->release(5);
                });
    }
}

Як бачите, подобаєтьсямаршрут проміжного програмного забезпечення, Middlware роботи отримує оброблювану роботу та зворотний виклик, який слід викликати для продовження обробки завдання.

Після створення проміжного програмного забезпечення, вони можуть бути приєднані до завдання, повернувши їх із робочого місцяmiddlewareметод. Цей метод не існує на робочих місцях, встановлених платформоюmake:jobКоманда ремісника, тому вам потрібно буде додати її до власного визначення класу роботи:

use App\Jobs\Middleware\RateLimited;

/**
 * Get the middleware the job should pass through.
 *
 * @return array
 */
public function middleware()
{
    return [new RateLimited];
}

Обмеження ставки

Хоча ми щойно продемонстрували, як написати власне Middlware для обмеження швидкості, Laravel включає Middlware, що обмежує швидкість, яке ви можете використовувати для оцінки обмежених завдань. Люблюобмежувачі швидкості маршруту, обмежувачі вакансій визначаються за допомогоюRateLimiterфасадніforметод.

Наприклад, ви можете дозволити користувачам робити резервні копії своїх даних раз на годину, не встановлюючи такого обмеження для преміум-клієнтів. Для цього ви можете визначити aRateLimiterу вашомуAppServiceProvider:

use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for('backups', function ($job) {
    return $job->user->vipCustomer()
                ? Limit::none()
                : Limit::perHour(1)->by($job->user->id);
});

Потім ви можете приєднати обмежувач швидкості до завдання резервного копіювання за допомогоюRateLimitedMiddlware. Кожного разу, коли завдання перевищує обмеження швидкості, це Middlware відпускає завдання назад у чергу з відповідною затримкою залежно від тривалості обмеження швидкості.

use Illuminate\Queue\Middleware\RateLimited;

/**
 * Get the middleware the job should pass through.
 *
 * @return array
 */
public function middleware()
{
    return [new RateLimited('backups')];
}

Повернення завдання із обмеженою швидкістю до черги все одно збільшить загальну кількість завданняattempts. Можливо, ви захочете налаштувати свійtriesіmaxExceptionsвластивостей класу вашої роботи відповідно. Або, можливо, ви захочете використовуватиretryUntilметодщоб визначити проміжок часу, доки робота більше не повинна виконуватися.

Якщо ви використовуєте Redis, ви можете використовуватиRateLimitedWithRedisMiddlware, яке досконало налаштовано для Redis і є більш ефективним, ніж базове обмеження проміжного програмного забезпечення.

Запобігання перекриванню робочих місць

Laravel включає aWithoutOverlappingMiddlware, яке дозволяє запобігати дублюванню завдань на основі довільного ключа. Це може бути корисно, коли завдання в черзі модифікує ресурс, який одночасно має змінюватись лише одним завданням.

Наприклад, уявімо, що у вас є робота з обробки відшкодування, і ви хочете, щоб запобігти дублюванню завдань відшкодування для того самого ідентифікатора замовлення. Для цього ви можете повернути файлWithoutOverlappingMiddlware від ваших завдань з обробки відшкодуванняmiddlewareметод:

use Illuminate\Queue\Middleware\WithoutOverlapping;

/**
 * Get the middleware the job should pass through.
 *
 * @return array
 */
public function middleware()
{
    return [new WithoutOverlapping($this->order->id)];
}

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

/**
 * Get the middleware the job should pass through.
 *
 * @return array
 */
public function middleware()
{
    return [(new WithoutOverlapping($this->order->id))->releaseAfter(60)];
}

Якщо ви хочете негайно видалити будь-які перекриваються завдання, ви можете використовуватиdontReleaseметод:

/**
 * Get the middleware the job should pass through.
 *
 * @return array
 */
public function middleware()
{
    return [(new WithoutOverlapping($this->order->id))->dontRelease()];
}
WithoutOverlappingMiddlware вимагає драйвера кешу, який підтримуєзамки.

Диспетчерські роботи

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

<?php

namespace App\Http\Controllers;

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

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

        ProcessPodcast::dispatch($podcast);
    }
}

Якщо ви хочете умовно відправити роботу, ви можете використовуватиdispatchIfіdispatchUnlessметоди:

ProcessPodcast::dispatchIf($accountActive === true, $podcast);

ProcessPodcast::dispatchUnless($accountSuspended === false, $podcast);

Затримка відправки

Якщо ви хочете відкласти виконання завдання в черзі, ви можете використовуватиdelayметод при відправленні роботи. Наприклад, вкажемо, що завдання має бути доступним для обробки лише через 10 хвилин після його відправлення:

<?php

namespace App\Http\Controllers;

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

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 хвилин.

Диспетчеризація після того, як відповідь надіслано браузеру

Крім того,dispatchAfterResponseметод затримує відправлення завдання, поки відповідь не буде надіслана в браузер користувача. Це все одно дозволить користувачеві почати користуватися програмою, навіть якщо завдання в черзі все ще виконується. Зазвичай це слід використовувати лише для завдань, які займають близько секунди, наприклад, надсилання електронного листа:

use App\Jobs\SendNotification;

SendNotification::dispatchAfterResponse();

Ви можетеdispatcha Закриття та ланцюжокafterResponseметоду на помічник для виконання Закриття після того, як відповідь буде надіслана браузеру:

use App\Mail\WelcomeMessage;
use Illuminate\Support\Facades\Mail;

dispatch(function () {
    Mail::to('taylor@laravel.com')->send(new WelcomeMessage);
})->afterResponse();

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

Якщо ви хочете негайно відправити роботу (синхронно), ви можете використовуватиdispatchSyncметод. При використанні цього методу завдання не буде в черзі і буде запущено негайно в рамках поточного процесу:

<?php

namespace App\Http\Controllers;

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

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

        ProcessPodcast::dispatchSync($podcast);
    }
}

Підключення робочих місць

Ланцюжок завдань дозволяє вказати список завдань, що стоять у черзі, які слід виконувати послідовно після успішного виконання основного завдання. Якщо одне завдання в послідовності не вдається, решта завдань не запускатимуться. Щоб виконати ланцюжок завдань, що стоять у черзі, ви можете використовуватиchainметод, передбаченийBusфасад:

use Illuminate\Support\Facades\Bus;

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

Окрім ланцюжка екземплярів робочих класів, ви також можете створити ланцюжок Закриття:

Bus::chain([
    new ProcessPodcast,
    new OptimizePodcast,
    function () {
        Podcast::update(...);
    },
])->dispatch();
Видалення завдань за допомогою$this->delete()метод не завадить обробляти ланцюгові завдання. Ланцюг зупинить виконання лише в тому випадку, якщо завдання в ланцюзі не вдається.

Мережеве підключення та черга

Якщо ви хочете вказати підключення та чергу, які слід використовувати для ланцюгових завдань, ви можете використовуватиonConnectionіonQueueметоди. Ці методи визначають підключення черги та ім'я черги, які слід використовувати, якщо завданням, що знаходяться в черзі, явно не призначено інше підключення / чергу:

Bus::chain([
    new ProcessPodcast,
    new OptimizePodcast,
    new ReleasePodcast,
])->onConnection('redis')->onQueue('podcasts')->dispatch();

Несправності ланцюга

При ланцюжку завдань ви можете використовуватиcatchметод, щоб вказати Закриття, яке слід викликати, якщо завдання в ланцюжку не вдається. Даний зворотний виклик отримає екземпляр винятку, який спричинив збій завдання:

use Illuminate\Support\Facades\Bus;
use Throwable;

Bus::chain([
    new ProcessPodcast,
    new OptimizePodcast,
    new ReleasePodcast,
])->catch(function (Throwable $e) {
    // A job within the chain has failed...
})->dispatch();

Налаштування черги та підключення

Відправка до певної черги

Переміщуючи завдання в різні черги, ви можете "класифікувати" свої завдання в черзі і навіть визначити пріоритет, скільки працівників ви призначите в різні черги. Майте на увазі, це не спрямовує завдання на різні "підключення" черги, як це визначено у вашому файлі конфігурації черги, а лише на конкретні черги в межах одного з'єднання. Щоб вказати чергу, використовуйтеonQueueметод при відправленні завдання:

<?php

namespace App\Http\Controllers;

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

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\Http\Controllers\Controller;
use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;

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');

Вказівка ​​максимальних спроб роботи / значень часу очікування

Макс. Спроб

Один із підходів до визначення максимальної кількості спроб роботи може бути здійснений через--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;
}

Спроби, засновані на часі

Як альтернативу визначенню того, скільки разів робота може бути виконана до того, як вона провалиться, ви можете визначити час, коли робота повинна робити час очікування. Це дозволяє виконати роботу будь-яку кількість разів протягом заданого періоду часу. Щоб визначити час, коли час роботи повинен закінчитися, додайте aretryUntilметод до вашого робочого класу:

/**
 * Determine the time at which the job should timeout.
 *
 * @return \DateTime
 */
public function retryUntil()
{
    return now()->addSeconds(5);
}
Ви також можете визначити aretryUntilметоду для ваших прослуховувачів подій, що стоять у черзі.

Макс. Винятки

Іноді вам може знадобитися вказати, що завдання може бути спробувано багато разів, але воно повинно провалитися, якщо повторні спроби ініціюються заданою кількістю винятків. Для цього ви можете визначити amaxExceptionsмайно на вашому робочому класі:

<?php

namespace App\Jobs;

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

    /**
     * The maximum number of exceptions to allow before failing.
     *
     * @var int
     */
    public $maxExceptions = 3;

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        Redis::throttle('key')->allow(10)->every(60)->then(function () {
            // Lock obtained, process the podcast...
        }, function () {
            // Unable to obtain lock...
            return $this->release(10);
        });
    }
}

У цьому прикладі завдання звільняється на десять секунд, якщо програма не може отримати блокування Redis і буде продовжувати повторюватися до 25 разів. Однак завдання не вдасться, якщо завдання призведе до трьох не оброблених винятків.

Timeout

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;
}

Іноді процеси блокування вводу-виводу, такі як сокети або вихідні з'єднання HTTP, можуть не відповідати вказаному часу очікування. Тому, використовуючи ці функції, ви завжди повинні намагатися вказати час очікування, використовуючи також їх API. Наприклад, використовуючи Guzzle, ви завжди повинні вказувати значення підключення та запитувати час очікування.

Обробка помилок

Якщо під час обробки завдання буде видано виняток, завдання буде автоматично випущено назад у чергу, тому його можна буде спробувати знову. Завдання продовжуватиме випускатися до тих пір, поки не буде здійснено спробу максимальну кількість разів, дозволених вашим додатком. Максимальна кількість спроб визначається--triesперемикач, що використовується наqueue:workartisan командування. Крім того, максимальна кількість спроб може бути визначена для самого класу завдань. Докладніше про запуск робочої чергиможна знайти нижче.

Розміщення робочих місць

Функція пакетного керування завданнями Laravel дозволяє вам легко виконати партію завдань, а потім виконати певні дії, коли партія завдань завершиться. Перш ніж розпочати, слід створити міграцію бази даних, щоб створити таблицю, яка міститиме метаінформацію про ваш пакет роботи. Ця міграція може бути створена за допомогоюqueue:batches-tableКоманда ремісників:

php artisan queue:batches-table

php artisan migrate

Визначення сумісних робочих місць

Ви повинні створити групову роботустворити завдання, що стоїть у черзіяк нормально; однак вам слід додатиIlluminate\Bus\Batchableриса до робочого класу. Ця риса забезпечує доступ доbatchметод, який може бути використаний для отримання поточної партії, в якій виконується завдання:

<?php

namespace App\Jobs;

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

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

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        if ($this->batch()->cancelled()) {
            // Detected cancelled batch...

            return;
        }

        // Batched job executing...
    }
}

Диспетчерські партії

Щоб відправити партію завдань, слід скористатисяbatchметодBusфасад. Звичайно, пакетне обслуговування в першу чергу корисно в поєднанні із зворотними викликами завершення. Отже, ви можете використовуватиthen,catch, іfinallyметоди визначення зворотних викликів завершення для пакета. Кожен із цих зворотних дзвінків отримаєIlluminate\Bus\Batchекземпляр, коли вони викликаються:

use App\Jobs\ProcessPodcast;
use App\Podcast;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;
use Throwable;

$batch = Bus::batch([
    new ProcessPodcast(Podcast::find(1)),
    new ProcessPodcast(Podcast::find(2)),
    new ProcessPodcast(Podcast::find(3)),
    new ProcessPodcast(Podcast::find(4)),
    new ProcessPodcast(Podcast::find(5)),
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->catch(function (Batch $batch, Throwable $e) {
    // First batch job failure detected...
})->finally(function (Batch $batch) {
    // The batch has finished executing...
})->dispatch();

return $batch->id;

Іменування партій

Деякі інструменти, такі як Laravel Horizon та Laravel Telescope, можуть надати більш зручну інформацію про налагодження пакетів, якщо партії названі. Щоб призначити партії довільне ім'я, ви можете зателефонувати доnameметод при визначенні партії:

$batch = Bus::batch([
    // ...
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->name('Process Podcasts')->dispatch();

Пакетне підключення та черга

Якщо ви хочете вказати підключення та чергу, які слід використовувати для пакетних завдань, ви можете використовуватиonConnectionіonQueueметоди:

$batch = Bus::batch([
    // ...
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->onConnection('redis')->onQueue('podcasts')->dispatch();

Ланцюги в межах партій

Ви можете додати набірприкуті роботивсередині партії, розмістивши ланцюгові завдання всередині масиву. Наприклад, ми можемо виконати два ланцюжки завдань паралельно. Оскільки обидві ланцюжки партіюються, ми зможемо перевірити прогрес завершення партії в цілому:

Bus::batch([
    [
        new ReleasePodcast(1),
        new SendPodcastReleaseNotification(1),
    ],
    [
        new ReleasePodcast(2),
        new SendPodcastReleaseNotification(2),
    ],
])->dispatch();

Додавання робочих місць до пакетів

Іноді може бути корисним додавання додаткових завдань до партії зсередини пакетного завдання. Цей шаблон може бути корисним, коли вам потрібно скласти тисячі завдань, які можуть надто довго надходити під час веб-запиту. Отже, замість цього, можливо, ви захочете відправити початкову партію завдань "навантажувача", які зволожують партію новими завданнями:

$batch = Bus::batch([
    new LoadImportBatch,
    new LoadImportBatch,
    new LoadImportBatch,
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->name('Import Contacts')->dispatch();

У цьому прикладі ми будемо використовуватиLoadImportBatchзавдання гідратувати партію додатковими робочими місцями. Для цього ми можемо використовуватиaddметод на екземплярі пакета, до якого можна отримати доступ в рамках завдання:

use App\Jobs\ImportContacts;
use Illuminate\Support\Collection;

/**
 * Execute the job.
 *
 * @return void
 */
public function handle()
{
    if ($this->batch()->cancelled()) {
        return;
    }

    $this->batch()->add(Collection::times(1000, function () {
        return new ImportContacts;
    }));
}
Додавати завдання до партії можна лише із задання, яке належить тій самій партії.

Огляд партій

Illuminate\Bus\BatchМетод, який надається для зворотного виклику пакетного завершення, має різноманітні властивості та методи, що допомагають вам взаємодіяти та перевіряти дану партію завдань.

// The UUID of the batch...
$batch->id;

// The name of the batch (if applicable)...
$batch->name;

// The number of jobs assigned to the batch...
$batch->totalJobs;

// The number of jobs that have not been processed by the queue...
$batch->pendingJobs;

// The number of jobs that have failed...
$batch->failedJobs;

// The number of jobs that have been processed thus far...
$batch->processedJobs();

// The completion percentage of the batch (0-100)...
$batch->progress();

// Indicates if the batch has finished executing...
$batch->finished();

// Cancel the execution of the batch...
$batch->cancel();

// Indicates if the batch has been cancelled...
$batch->cancelled();

Повернення пакетів з маршрутів

ВсіIlluminate\Bus\Batchекземпляри можна JSON серіалізувати, тобто ви можете повернути їх безпосередньо з одного із маршрутів вашої програми, щоб отримати корисне навантаження JSON, що містить інформацію про пакет, включаючи хід його завершення. Щоб отримати партію за її ідентифікатором, ви можете використовуватиBusфасадніfindBatchметод:

use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Route;

Route::get('/batch/{batchId}', function (string $batchId) {
    return Bus::findBatch($batchId);
});

Скасування пакетів

Іноді може знадобитися скасувати виконання даної партії. Це можна зробити, зателефонувавши доcancelметод наIlluminate\Bus\Batchпримірник:

/**
 * Execute the job.
 *
 * @return void
 */
public function handle()
{
    if ($this->user->exceedsImportLimit()) {
        return $this->batch()->cancel();
    }

    if ($this->batch()->cancelled()) {
        return;
    }
}

Пакетні помилки

Коли пакетне завдання не вдається,catchбуде викликаний зворотний виклик (якщо призначений). Цей зворотний виклик викликається лише для завдання, яке не вдається виконати в пакетному режимі.

Допущення збоїв

Коли завдання в партії не вдається, Laravel автоматично позначить партію як "скасовану". За бажанням ви можете вимкнути цю поведінку, щоб відмова в роботі автоматично не позначив пакет як скасований. Це може бути здійснено за допомогою викликуallowFailuresметод під час відправлення партії:

$batch = Bus::batch([
    // ...
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->allowFailures()->dispatch();

Повторна спроба невдалих пакетних завдань

Для зручності Laravel пропонуєqueue:retry-batchКоманда Artisan, яка дозволяє легко повторити всі невдалі завдання для даної партії.queue:retry-batchкоманда приймає UUID пакета, чиї невдалі завдання слід повторити:

php artisan queue:retry-batch 32dbc76c-4f82-4749-b610-a639fe0099b5

Закриття в черзі

Замість відправлення класу завдань до черги, ви також можете надіслати Закриття. Це чудово підходить для швидких, простих завдань, які потрібно виконувати поза поточним циклом запиту. При відправленні Закриття до черги вміст коду Закриття підписується криптографічно, тому його не можна змінювати при передачі:

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

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

Використанняcatchметодом, ви можете надати Закриття, яке слід виконати, якщо Закриття в черзі не вдається успішно завершити після вичерпання всіх налаштованих спроб спроби повторної спроби у вашій черзі:

use Throwable;

dispatch(function () use ($podcast) {
    $podcast->publish();
})->catch(function (Throwable $e) {
    // This job has failed...
});

Запуск програми черги

Laravel включає працівника черги, який буде обробляти нові завдання, коли їх надсилатимуть у чергу. Ви можете запустити працівника за допомогоюqueue:workartisan командування. Зверніть увагу, що один разqueue:workкоманда запущена, вона буде продовжувати працювати, доки не буде зупинена вручну або ви не закриєте термінал:

php artisan queue:work
Зберігатиqueue:workпроцес, який постійно працює у фоновому режимі, слід використовувати монітор процесу, такий якКерівникщоб переконатися, що працівник черги не припиняє працювати.

Пам'ятайте, що працівники черги - це довгоживучі процеси, які зберігають завантажений стан програми в пам'яті. Як результат, вони не помітять змін у вашій базі коду після їх запуску. Отже, під час процесу розгортання обов’язковоперезапустіть працівників черги. Крім того, пам’ятайте, що будь-який статичний стан, створений або змінений вашою програмою, не буде автоматично скидатися між завданнями.

Крім того, ви можете запуститиqueue:listenкоманди. При використанніqueue:listenкоманда, вам не потрібно вручну перезапускати працівника, коли ви хочете перезавантажити ваш оновлений код або скинути стан програми; однак ця команда не така ефективна, якqueue:work:

php artisan queue:listen

Вказівка ​​підключення та черги

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

php artisan queue:work redis

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

php artisan queue:work redis --queue=emails

Обробка заданої кількості робочих місць

--onceОпція може бути використана для інструктування працівника обробляти лише одне завдання з черги:

php artisan queue:work --once

--max-jobsваріант може бути використаний, щоб доручити працівникові обробити задану кількість завдань, а потім вийти. Цей параметр може бути корисним у поєднанні зКерівниктак що ваші працівники будуть автоматично перезапущені після обробки заданої кількості завдань:

php artisan queue:work --max-jobs=1000

Обробка всіх завдань, що стоять у черзі, а потім вихід

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

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

Обробка завдань протягом заданої кількості секунд

--max-timeОпція може бути використана, щоб доручити працівникові обробити завдання протягом заданої кількості секунд, а потім вийти. Цей параметр може бути корисним у поєднанні зКерівникщоб ваші працівники автоматично перезапускались після обробки завдань протягом певного періоду часу:

// Process jobs for one hour and then exit...
php artisan queue:work --max-time=3600

Міркування щодо ресурсів

Працівники черги демонів не «перезавантажують» фреймворк перед обробкою кожного завдання. Тому ви повинні звільнити важкі ресурси після виконання кожної роботи. Наприклад, якщо ви виконуєте обробку зображень за допомогою бібліотеки GD, вам слід звільнити пам'ять за допомогоюimagedestroyколи закінчите.

Пріоритети черги

Іноді вам може знадобитися визначити пріоритет, як обробляються ваші черги. Наприклад, у вашомуconfig/queue.phpВи можете встановити за замовчуваннямqueueдля вашогоredisпідключення доlow. Однак іноді, можливо, ви захочете підштовхнути роботу доhighпріоритетна черга приблизно так:

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

Щоб запустити працівника, який перевіряє, що всіhighзавдання черги обробляються перед тим, як перейти до будь-яких завдань наlowчерзі, передайте список назв черг, розділених комами, вworkкоманда:

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

Робітники черги та розгортання

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

php artisan queue:restart

Ця команда дасть вказівку всім працівникам черги витончено "померти" після того, як вони закінчать обробку свого поточного завдання, щоб жодна існуюча робота не була втрачена. Так як працівники черги загинуть, колиqueue:restartкоманда виконується, ви повинні запускати менеджер процесів, такий якКерівникдля автоматичного перезапуску працівників черги.

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

Термін дії та час очікування

Закінчення роботи

У вашомуconfig/queue.phpфайл конфігурації, кожне підключення черги визначає aretry_afterваріант. Цей параметр визначає, скільки секунд слід чекати підключення до черги перед повторною спробою завдання, яке обробляється. Наприклад, якщо значенняretry_afterвстановлено на90, завдання буде випущено назад у чергу, якщо воно оброблялося протягом 90 секунд без видалення. Як правило, слід встановитиretry_afterзначення до максимальної кількості секунд, які ваші робочі місця повинні прийняти розумно, щоб завершити обробку.

Єдине підключення до черги, яке не міститьretry_afterзначення - SQS Amazon. SQS повторить спробу завдання на основіТиповий час очікування видимостіякий керується в консолі AWS.

Час очікування працівника

queue:workКомандування ремісників викриває a--timeoutваріант.--timeoutПараметр вказує, скільки часу буде чекати головний процес черги Laravel, перш ніж вбивати дочірнього працівника черги, який обробляє завдання. Іноді процес дочірньої черги може з різних причин «заморозитися».--timeoutПараметр видаляє заморожені процеси, які перевищили вказаний часовий ліміт:

php artisan queue:work --timeout=60

retry_afterпараметр конфігурації та--timeoutПараметри CLI різні, але працюйте разом, щоб гарантувати, що робочі місця не втрачаються і що завдання успішно обробляються лише один раз.

--timeoutзначення завжди має бути принаймні на кілька секунд коротше вашогоretry_afterзначення конфігурації. Це забезпечить, щоб працівник, який обробляє дане завдання, завжди був убитий перед тим, як його повторити. Якщо ти--timeoutваріант довший за вашretry_afterзначення конфігурації, ваші завдання можуть бути оброблені двічі.

Тривалість сну працівника

Коли завдання доступні в черзі, працівник продовжить обробку завдань без затримки між ними. ОднакsleepОпція визначає, як довго (у секундах) працівник буде "спати", якщо нових робочих місць немає. Під час сну працівник не буде обробляти жодної нової роботи - робота буде оброблена після того, як робітник знову прокинеться.

php artisan queue:work --sleep=3

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

Встановлення Supervisor

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

sudo apt-get install supervisor
Якщо налаштування супервізора самостійно здається вражаючим, рекомендуємо використовуватиКузня Laravel, який автоматично встановить і налаштує Supervisor для ваших проектів Laravel.

Налаштування супервізора

Файли конфігурації супервізора зазвичай зберігаються в/etc/supervisor/conf.dкаталог. У цьому каталозі ви можете створити будь-яку кількість файлів конфігурації, які вказують керівнику, як слід контролювати ваші процеси. Наприклад, давайте створимо файлlaravel-worker.confфайл, який запускається та контролює aqueue: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 --max-time=3600
autostart=true
autorestart=true
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/home/forge/app.com/worker.log
stopwaitsecs=3600

У цьому прикладіnumprocsдиректива доручить супервізору запустити 8queue:workобробляє та контролює всі з них, автоматично перезапускаючи їх, якщо вони не вдаються. Вам слід змінитиqueue:work sqsчастинаcommandдирективи, щоб відобразити бажане з'єднання з чергою

Ви повинні переконатися, що значенняstopwaitsecsбільше, ніж кількість секунд, витрачених вашим найдовшим завданням. В іншому випадку Супервайзер може вбити завдання до його обробки.

Початковий керівник

Після створення файлу конфігурації ви можете оновити конфігурацію супервізора та запустити процеси, використовуючи такі команди:

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 перед повторною спробою завдання, яке не вдалося використати--backoffваріант. За замовчуванням завдання негайно повторюється:

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

Якщо ви хочете налаштувати затримку повторної спроби невдалого завдання для кожного завдання, ви можете зробити це, визначивши abackoffмайно у вашому класі роботи в черзі:

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

Якщо вам потрібна більш складна логіка для визначення затримки повторної спроби, ви можете визначити abackoffу вашому робочому класі в черзі:

/**
* Calculate the number of seconds to wait before retrying the job.
*
* @return int
*/
public function backoff()
{
    return 3;
}

Ви можете легко налаштувати "експоненціальні" резервні копії, повернувши масив змінних значень ізbackoffметод. У цьому прикладі затримка повторної спроби становитиме 1 секунду для першої спроби, 5 секунд для другої спроби та 10 секунд для третьої спроби:

/**
* Calculate the number of seconds to wait before retrying the job.
*
* @return array
*/
public function backoff()
{
    return [1, 5, 10];
}

Прибирання після невдалих робіт

Ви можете визначити afailedметод безпосередньо на вашому робочому класі, що дозволяє виконувати конкретне очищення роботи, коли виникає несправність. Це ідеальне місце, щоб надіслати Notification своїм користувачам або скасувати будь-які дії, виконані завданням.Throwableвиняток, який спричинив помилку завдання, буде передано доfailedметод:

<?php

namespace App\Jobs;

use App\Models\Podcast;
use App\Services\AudioProcessor;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Throwable;

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

    protected $podcast;

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

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

    /**
     * Handle a job failure.
     *
     * @param  \Throwable  $exception
     * @return void
     */
    public function failed(Throwable $exception)
    {
        // Send user notification of failure, etc...
    }
}

Помилка роботи

Якщо ви хочете зареєструвати подію, яка буде викликана, коли завдання не вдасться, ви можете використовуватиQueue::failingметод. Ця подія - чудова можливість повідомити свою команду електронною поштою абоОслаблення. Наприклад, ми можемо приєднати зворотний дзвінок до цієї події зAppServiceProviderщо входить до складу Laravel:

<?php

namespace App\Providers;

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

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таблиці бази даних, ви можете використовуватиqueue:failedКоманда ремісників:

php artisan queue:failed

queue:failedкоманда перелічить ідентифікатор завдання, підключення, чергу, час відмов та іншу інформацію про роботу. Ідентифікатор завдання може бути використаний для повторної спроби невдалого завдання. Наприклад, повторити спробу невдалого завдання з ідентифікатором5, виконайте таку команду:

php artisan queue:retry 5

За необхідності ви можете передати декілька ідентифікаторів або діапазон ідентифікаторів (при використанні числових ідентифікаторів) команді:

php artisan queue:retry 5 6 7 8 9 10

php artisan queue:retry --range=5-10

Щоб повторити всі невдалі завдання, виконайтеqueue:retryкомандувати та передаватиallяк ідентифікатор:

php artisan queue:retry all

Якщо ви хочете видалити невдале завдання, ви можете використовуватиqueue:forgetкоманда:

php artisan queue:forget 5
Під час використанняГоризонт, вам слід використовуватиhorizon:forgetкоманда видалити невдале завдання замістьqueue:forgetкоманди.

Щоб видалити всі свої невдалі завдання, ви можете використовуватиqueue:flushкоманда:

php artisan queue:flush

Ігнорування відсутніх моделей

При введенні красномовної моделі в завдання вона автоматично серіалізується перед тим, як розміщуватись у черзі, і відновлюється при обробці завдання. Однак якщо модель була видалена, поки завдання чекало на обробку працівником, ваше завдання може провалитись ізModelNotFoundException.

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

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

Очищення робочих місць із черг

Під час використанняГоризонт, вам слід використовуватиhorizon:clearкоманда для очищення завдань з черги замістьqueue:clearкоманди.

Якщо ви хочете видалити всі завдання із черги за замовчуванням підключення за замовчуванням, ви можете зробити це за допомогоюqueue:clearКоманда ремісників:

php artisan queue:clear

Ви також можете надатиconnectionаргумент іqueueможливість видалення завдань із певного підключення та черги:

php artisan queue:clear redis --queue=emails
Видалення завдань із черг доступне лише для драйверів черги SQS, Redis та бази даних. Крім того, процес видалення повідомлення SQS займає до 60 секунд, тому завдання, надіслані до черги SQS до 60 секунд після очищення черги, також можуть бути видалені.

Події роботи

Використання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фасад, ви можете вказати зворотні виклики, які виконуються до того, як працівник намагається отримати завдання з черги. Наприклад, ви можете зареєструвати закриття для відкату будь-яких транзакцій, які залишились відкритими раніше невдалим завданням:

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