<? phpukraine ДОКУМЕНТАЦІЯ
Пошук по платформі
Документація українською

Переклад силами спільноти. Кожен розділ показує стан готовності — недоперекладене відкрито помічене, а не приховане.

ВЕРСІЯ
АКТУАЛЬНА Актуальний реліз. Переклад наздоганяє оригінал — розділи з низьким відсотком позначені у змісті.
ПОГЛИБЛЕНО · ЧАСТКОВО частковий переклад, оновлено 4 вересня 2026

Черги — Laravel

ПЕРЕКЛАД НЕПОВНИЙ

Частину підрозділів ще не перекладено — вони показані англійською нижче в тексті або лишились в оригіналі. Готові фрагменти вже перевірені редактором.

Під час створення вебзастосунку у вас можуть бути завдання, як-от розбір і збереження завантаженого CSV-файлу, які виконуються надто довго для типового вебзапиту. На щастя, Laravel дозволяє легко створювати завдання (job) у чергах, що можуть оброблятися у фоні. Переносячи тривалі за часом завдання в чергу, ваш застосунок може відповідати на вебзапити блискавично швидко й забезпечувати кращий досвід для ваших клієнтів.

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

Параметри конфігурації черг Laravel зберігаються у файлі конфігурації config/queue.php вашого застосунку. У цьому файлі ви знайдете конфігурації зʼєднань для кожного з драйверів черг, що входять до складу фреймворку, зокрема драйверів database, Amazon SQS, Redis та Beanstalkd, а також синхронного драйвера, який виконуватиме завдання негайно (для використання під час розробки або тестування). Також включено драйвер черги null, який відкидає завдання з черги.

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

Зʼєднання проти черг

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

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

use App\Jobs\ProcessPodcast;

// Це завдання надсилається до черги за замовчуванням зʼєднання за замовчуванням...
ProcessPodcast::dispatch();

// Це завдання надсилається до черги "emails" зʼєднання за замовчуванням...
ProcessPodcast::dispatch()->onQueue('emails');

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

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

Нотатки щодо драйверів і передумови

База даних

Щоб використовувати драйвер черги database, вам знадобиться таблиця бази даних для зберігання завдань. Зазвичай вона включена до стандартної міграції бази даних Laravel 0001_01_01_000002_create_jobs_table.php; однак, якщо ваш застосунок не містить цієї міграції, ви можете скористатися Artisan-командою make:queue-table, щоб її створити:

php artisan make:queue-table

php artisan migrate

Redis

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

Попередження. Параметри Redis serializer і compression не підтримуються драйвером черги redis.

Redis Cluster

Якщо ваше зʼєднання черги Redis використовує Redis Cluster, імена ваших черг мають містити key hash tag. Це потрібно для того, щоб гарантувати, що всі ключі Redis для певної черги потраплять в один хеш-слот:

'redis' => [
    'driver' => 'redis',
    'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
    'queue' => env('REDIS_QUEUE', '{default}'),
    'retry_after' => env('REDIS_QUEUE_RETRY_AFTER', 90),
    'block_for' => null,
    'after_commit' => false,
],
Блокування

Використовуючи чергу Redis, ви можете застосувати параметр конфігурації block_for, щоб указати, як довго драйвер має чекати на появу доступного завдання, перш ніж перейти до наступної ітерації циклу обробника й повторно опитати базу даних Redis.

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

'redis' => [
    'driver' => 'redis',
    'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
    'queue' => env('REDIS_QUEUE', 'default'),
    'retry_after' => env('REDIS_QUEUE_RETRY_AFTER', 90),
    'block_for' => 5,
    'after_commit' => false,
],

Попередження. Встановлення block_for у 0 призведе до того, що обробники черги блокуватимуться нескінченно, доки не зʼявиться доступне завдання. Це також завадить обробці сигналів на кшталт SIGTERM, доки не буде оброблено наступне завдання.

Сховище переповнення SQS

Amazon SQS обмежує максимальний розмір корисного навантаження (payload) повідомлення в черзі. Якщо вам потрібно диспетчеризувати завдання з корисним навантаженням, яке може перевищувати цей ліміт, ви можете налаштувати Laravel зберігати завеликі корисні навантаження SQS у сховищі кешу й надсилати через SQS лише вказівник на них. Щоб увімкнути цю можливість, додайте масив overflow до конфігурації вашого зʼєднання черги SQS:

'sqs' => [
    'driver' => 'sqs',
    'key' => env('AWS_ACCESS_KEY_ID'),
    'secret' => env('AWS_SECRET_ACCESS_KEY'),
    'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
    'queue' => env('SQS_QUEUE', 'default'),
    'suffix' => env('SQS_SUFFIX'),
    'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
    'after_commit' => false,
    'overflow' => [
        'enabled' => env('SQS_OVERFLOW_ENABLED', false),
        'store' => env('SQS_OVERFLOW_STORE'),
        'always' => false,
        'delete_after_processing' => true,
        'flush_on_clear' => env('SQS_OVERFLOW_FLUSH_ON_CLEAR', false),
    ],
],

Коли сховище переповнення ввімкнено, Laravel зберігатиме корисні навантаження розміром щонайменше 1 МБ у налаштованому сховищі кешу. Якщо параметр always має значення true, кожне корисне навантаження SQS зберігатиметься у сховищі кешу незалежно від його розміру. Оскільки завданням у черзі потрібно буде отримувати свої корисні навантаження зі сховища кешу під час обробки, вам слід обрати сховище, яке здатне зберігати ці корисні навантаження, доки ваші обробники їх не опрацюють. За замовчуванням збережені корисні навантаження видаляються після того, як їхні завдання були успішно оброблені й видалені з SQS.

Якщо параметр flush_on_clear має значення true, налаштоване сховище кешу переповнення буде очищено, коли команда queue:clear очищає чергу SQS. Оскільки очищення сховища кешу може видалити всі елементи з цього сховища, вам слід налаштувати сховище переповнення SQS на використання окремого виділеного сховища кешу, коли ви вмикаєте цей параметр.

Передумови інших драйверів

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

  • Amazon SQS: aws/aws-sdk-php ~3.0
  • Beanstalkd: pda/pheanstalk ~5.0
  • Redis: predis/predis ~3.0 або PHP-розширення phpredis
  • MongoDB: mongodb/laravel-mongodb

Створення завдань

Генерація класів завдань

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

php artisan make:job ProcessPodcast

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

Примітка. Заготовки (stubs) завдань можна кастомізувати за допомогою публікації заготовок.

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

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

<?php

namespace App\Jobs;

use App\Models\Podcast;
use App\Services\AudioProcessor;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;

class ProcessPodcast implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new job instance.
     */
    public function __construct(
        public Podcast $podcast,
    ) {}

    /**
     * Execute the job.
     */
    public function handle(AudioProcessor $processor): void
    {
        // Обробка завантаженого подкасту...
    }
}

У цьому прикладі зверніть увагу, що ми змогли передати модель Eloquent безпосередньо в конструктор завдання в черзі. Завдяки трейту Queueable, який використовує це завдання, моделі Eloquent та їхні завантажені звʼязки будуть коректно серіалізовані й десеріалізовані під час обробки завдання.

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

Впровадження залежностей у метод handle

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

Якщо ви хочете отримати повний контроль над тим, як контейнер впроваджує залежності в метод handle, ви можете скористатися методом контейнера bindMethod. Метод bindMethod приймає колбек, який отримує завдання і контейнер. У межах колбеку ви вільні викликати метод handle як забажаєте. Зазвичай цей метод слід викликати з методу boot вашого сервіс-провайдера App\Providers\AppServiceProvider:

use App\Jobs\ProcessPodcast;
use App\Services\AudioProcessor;
use Illuminate\Contracts\Foundation\Application;

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

Попередження. Бінарні дані, як-от сирий вміст зображення, слід пропускати через функцію base64_encode, перш ніж передавати їх у завдання в черзі. Інакше завдання може некоректно серіалізуватися в JSON під час розміщення в черзі.

Звʼязки в чергах

Оскільки всі завантажені звʼязки моделей Eloquent також серіалізуються, коли завдання потрапляє в чергу, серіалізований рядок завдання іноді може стати доволі великим. Крім того, коли завдання десеріалізується і звʼязки моделей повторно отримуються з бази даних, вони отримуватимуться повністю. Будь-які попередні обмеження звʼязку, застосовані до моделі перед її серіалізацією в процесі постановки завдання в чергу, не будуть застосовані під час десеріалізації завдання. Тому, якщо ви хочете працювати з підмножиною певного звʼязку, вам слід повторно накласти обмеження на цей звʼязок у вашому завданні в черзі.

Або, щоб запобігти серіалізації звʼязків, ви можете викликати метод withoutRelations на моделі під час встановлення значення властивості. Цей метод поверне екземпляр моделі без її завантажених звʼязків:

/**
 * Create a new job instance.
 */
public function __construct(
    Podcast $podcast,
) {
    $this->podcast = $podcast->withoutRelations();
}

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

$this->podcast = $podcast->withoutRelation('comments');

Якщо ви використовуєте просування властивостей конструктора PHP і хочете вказати, що звʼязки моделі Eloquent не слід серіалізувати, ви можете скористатися атрибутом WithoutRelations:

use Illuminate\Queue\Attributes\WithoutRelations;

/**
 * Create a new job instance.
 */
public function __construct(
    #[WithoutRelations]
    public Podcast $podcast,
) {}

Для зручності, якщо ви хочете серіалізувати всі моделі без звʼязків, ви можете застосувати атрибут WithoutRelations до всього класу замість того, щоб застосовувати атрибут до кожної моделі:

<?php

namespace App\Jobs;

use App\Models\DistributionPlatform;
use App\Models\Podcast;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Queue\Attributes\WithoutRelations;

#[WithoutRelations]
class ProcessPodcast implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new job instance.
     */
    public function __construct(
        public Podcast $podcast,
        public DistributionPlatform $platform,
    ) {}
}

Якщо завдання отримує колекцію або масив моделей Eloquent замість однієї моделі, звʼязки моделей у цій колекції не будуть відновлені під час десеріалізації та виконання завдання. Це зроблено для того, щоб запобігти надмірному використанню ресурсів у завданнях, які працюють із великою кількістю моделей.

Унікальні завдання

Попередження. Унікальні завдання потребують драйвера кешу, який підтримує блокування. Наразі атомарні блокування підтримують драйвери кешу memcached, redis, dynamodb, database, file і array.

Попередження. Обмеження унікальності завдань не застосовуються до завдань у пакетах (batches).

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

<?php

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

class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
    // ...
}

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

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

<?php

namespace App\Jobs;

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

#[UniqueFor(3600)]
class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
    /**
     * The product instance.
     *
     * @var \App\Models\Product
     */
    public $product;

    /**
     * Get the unique ID for the job.
     */
    public function uniqueId(): string
    {
        return $this->product->id;
    }
}

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

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

Збереження унікальності завдань до початку обробки

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

<?php

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;

class UpdateSearchIndex implements ShouldQueue, ShouldBeUniqueUntilProcessing
{
    // ...
}

Блокування унікальних завдань

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

use Illuminate\Contracts\Cache\Repository;
use Illuminate\Support\Facades\Cache;

class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
    // ...

    /**
     * Get the cache driver for the unique job lock.
     */
    public function uniqueVia(): Repository
    {
        return Cache::driver('redis');
    }
}

Примітка. Якщо вам потрібно лише обмежити паралельну обробку завдання, скористайтеся натомість job middleware WithoutOverlapping.

Завдання з дебаунсом

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

<?php

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Queue\Attributes\DebounceFor;

#[DebounceFor(30)]
class UpdateSearchIndex implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new job instance.
     */
    public function __construct(public int $productId)
    {
    }

    /**
     * Get the debounce ID for the job.
     */
    public function debounceId(): string
    {
        return (string) $this->productId;
    }
}

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

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

#[DebounceFor(30, maxWait: 120)]
class UpdateSearchIndex implements ShouldQueue
{
    use Queueable;

    // ...
}

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

use Illuminate\Contracts\Cache\Repository;
use Illuminate\Support\Facades\Cache;

public function debounceVia(): Repository
{
    return Cache::driver('redis');
}

Якщо завдання з дебаунсом витісняється новішою диспетчеризацією, Laravel відправить подію Illuminate\Queue\Events\JobDebounced і видалить витіснене завдання з черги.

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

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

Зашифровані завдання

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

<?php

use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;

class UpdateSearchIndex implements ShouldQueue, ShouldBeEncrypted
{
    // ...
}

Job Middleware

Job middleware дозволяють обгортати власну логіку навколо виконання завдань у черзі, зменшуючи кількість шаблонного коду в самих завданнях. Наприклад, розгляньте наступний метод handle, який використовує можливості обмеження частоти (rate limiting) Redis у Laravel, щоб дозволити обробку лише одного завдання кожні пʼять секунд:

use Illuminate\Support\Facades\Redis;

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

        // Обробка завдання...
    }, function () {
        // Не вдалося отримати блокування...

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

Хоча цей код і робочий, реалізація методу handle стає «шумною», оскільки захаращена логікою обмеження частоти Redis. Крім того, цю логіку обмеження частоти доведеться дублювати для будь-яких інших завдань, для яких ми хочемо обмежити частоту. Замість обмеження частоти в методі handle ми могли б визначити job middleware, який обробляє обмеження частоти:

<?php

namespace App\Jobs\Middleware;

use Closure;
use Illuminate\Support\Facades\Redis;

class RateLimited
{
    /**
     * Process the queued job.
     *
     * @param  \Closure(object): void  $next
     */
    public function handle(object $job, Closure $next): void
    {
        Redis::throttle('key')
            ->block(0)->allow(1)->every(5)
            ->then(function () use ($job, $next) {
                // Блокування отримано...

                $next($job);
            }, function () use ($job) {
                // Не вдалося отримати блокування...

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

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

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

use App\Jobs\Middleware\RateLimited;

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

Примітка. Job middleware також можна призначати слухачам подій у чергах, mailable-класам і сповіщенням.

Обмеження частоти

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

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

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    RateLimiter::for('backups', function (object $job) {
        return $job->user->vipCustomer()
            ? Limit::none()
            : Limit::perHour(1)->by($job->user->id);
    });
}

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

return Limit::perMinute(50)->by($job->user->id);

Щойно ви визначили своє обмеження частоти, ви можете прикріпити обмежувач частоти до вашого завдання за допомогою middleware Illuminate\Queue\Middleware\RateLimited. Щоразу, коли завдання перевищує обмеження частоти, цей middleware повертатиме завдання назад у чергу з відповідною затримкою на основі тривалості обмеження частоти:

use Illuminate\Queue\Middleware\RateLimited;

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

Повернення завдання з обмеженою частотою назад у чергу все одно збільшуватиме загальну кількість спроб (attempts) завдання. Ви можете відповідно налаштувати атрибути Tries і MaxExceptions у вашому класі завдання. Або ви можете скористатися методом retryUntil, щоб визначити проміжок часу, після якого завдання більше не слід намагатися виконати.

За допомогою методу releaseAfter ви також можете вказати кількість секунд, які мають минути, перш ніж повернене завдання буде спробувано знову:

/**
 * Get the middleware the job should pass through.
 *
 * @return array<int, object>
 */
public function middleware(): array
{
    return [(new RateLimited('backups'))->releaseAfter(60)];
}

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

/**
 * Get the middleware the job should pass through.
 *
 * @return array<int, object>
 */
public function middleware(): array
{
    return [(new RateLimited('backups'))->dontRelease()];
}

Обмеження частоти з Redis

Якщо ви використовуєте Redis, ви можете скористатися middleware Illuminate\Queue\Middleware\RateLimitedWithRedis, який точно налаштований під Redis і ефективніший за базовий middleware обмеження частоти:

use Illuminate\Queue\Middleware\RateLimitedWithRedis;

public function middleware(): array
{
    return [new RateLimitedWithRedis('backups')];
}

Метод connection можна використовувати, щоб указати, яке зʼєднання Redis має використовувати middleware:

return [(new RateLimitedWithRedis('backups'))->connection('limiter')];

Запобігання накладанню завдань

Laravel містить middleware Illuminate\Queue\Middleware\WithoutOverlapping, який дозволяє запобігти накладанню завдань на основі довільного ключа. Це може бути корисним, коли завдання в черзі змінює ресурс, який має змінюватися лише одним завданням за раз.

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

use Illuminate\Queue\Middleware\WithoutOverlapping;

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

Повернення завдання, що накладається, назад у чергу все одно збільшуватиме загальну кількість спроб завдання. Ви можете відповідно налаштувати атрибути Tries і MaxExceptions у вашому класі завдання. Наприклад, залишення Tries рівним 1, як за замовчуванням, завадить будь-якому завданню, що накладається, бути повтореним пізніше.

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

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

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

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

Middleware WithoutOverlapping працює на основі можливості атомарних блокувань Laravel. Іноді ваше завдання може несподівано впасти або завершитися за таймаутом так, що блокування не буде звільнено. Тому ви можете явно визначити час закінчення терміну дії блокування за допомогою методу expireAfter. Наприклад, наведений нижче приклад вкаже Laravel звільнити блокування WithoutOverlapping через три хвилини після початку обробки завдання:

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

Попередження. Middleware WithoutOverlapping потребує драйвера кешу, який підтримує блокування. Наразі атомарні блокування підтримують драйвери кешу memcached, redis, dynamodb, database, file і array.

Спільні ключі блокування між класами завдань

За замовчуванням middleware WithoutOverlapping запобігатиме накладанню лише завдань того самого класу. Тож, хоча два різні класи завдань можуть використовувати той самий ключ блокування, їм не буде заборонено накладатися. Однак ви можете вказати Laravel застосовувати ключ між класами завдань за допомогою методу shared:

use Illuminate\Queue\Middleware\WithoutOverlapping;

class ProviderIsDown
{
    // ...

    public function middleware(): array
    {
        return [
            (new WithoutOverlapping("status:{$this->provider}"))->shared(),
        ];
    }
}

class ProviderIsUp
{
    // ...

    public function middleware(): array
    {
        return [
            (new WithoutOverlapping("status:{$this->provider}"))->shared(),
        ];
    }
}

Тротлінг винятків

Laravel містить middleware Illuminate\Queue\Middleware\ThrottlesExceptions, який дозволяє застосовувати тротлінг до винятків. Щойно завдання викине задану кількість винятків, усі подальші спроби виконати завдання відкладаються, доки не мине вказаний часовий інтервал. Цей middleware особливо корисний для завдань, які взаємодіють зі сторонніми сервісами, що є нестабільними.

Наприклад, уявімо завдання в черзі, яке взаємодіє зі стороннім API, що починає викидати винятки. Щоб застосувати тротлінг до винятків, ви можете повернути middleware ThrottlesExceptions із методу middleware вашого завдання. Зазвичай цей middleware слід поєднувати із завданням, що реалізує спроби на основі часу:

use DateTime;
use Illuminate\Queue\Middleware\ThrottlesExceptions;

/**
 * Get the middleware the job should pass through.
 *
 * @return array<int, object>
 */
public function middleware(): array
{
    return [new ThrottlesExceptions(10, 5 * 60)];
}

/**
 * Determine the time at which the job should timeout.
 */
public function retryUntil(): DateTime
{
    return now()->plus(minutes: 30);
}

Перший аргумент конструктора, який приймає middleware, — це кількість винятків, які завдання може викинути, перш ніж до нього буде застосовано тротлінг, а другий аргумент конструктора — кількість секунд, які мають минути, перш ніж завдання буде спробовано знову після застосування тротлінгу. У наведеному вище прикладі коду, якщо завдання викине 10 послідовних винятків, ми зачекаємо 5 хвилин, перш ніж спробувати виконати завдання знову, з обмеженням у 30-хвилинний ліміт часу.

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

use Illuminate\Queue\Middleware\ThrottlesExceptions;

/**
 * Get the middleware the job should pass through.
 *
 * @return array<int, object>
 */
public function middleware(): array
{
    return [(new ThrottlesExceptions(10, 5 * 60))->backoff(5)];
}

Метод backoff також приймає замикання, яке отримує викинутий виняток, дозволяючи визначати затримку динамічно:

use App\Exceptions\RateLimitedException;
use Illuminate\Queue\Middleware\ThrottlesExceptions;
use Throwable;

/**
 * Get the middleware the job should pass through.
 *
 * @return array<int, object>
 */
public function middleware(): array
{
    return [(new ThrottlesExceptions(10, 5 * 60))->backoff(
        fn (Throwable $throwable) => $throwable instanceof RateLimitedException
            ? $throwable->retryAfterMinutes()
            : 5
    )];
}

Усередині цей middleware використовує систему кешу Laravel для реалізації обмеження частоти, а імʼя класу завдання використовується як «ключ» кешу. Ви можете перевизначити цей ключ, викликавши метод by під час прикріплення middleware до вашого завдання. Це може бути корисним, якщо у вас є кілька завдань, які взаємодіють із тим самим стороннім сервісом, і ви хочете, щоб вони спільно використовували загальний «кошик» тротлінгу, гарантуючи дотримання єдиного спільного ліміту:

use Illuminate\Queue\Middleware\ThrottlesExceptions;

/**
 * Get the middleware the job should pass through.
 *
 * @return array<int, object>
 */
public function middleware(): array
{
    return [(new ThrottlesExceptions(10, 10 * 60))->by('key')];
}

За замовчуванням цей middleware застосовуватиме тротлінг до кожного винятку. Ви можете змінити цю поведінку, викликавши метод when під час прикріплення middleware до вашого завдання. Тоді тротлінг до винятку буде застосовано лише в разі, якщо замикання, передане в метод when, повертає true:

use Illuminate\Http\Client\HttpClientException;
use Illuminate\Queue\Middleware\ThrottlesExceptions;

/**
 * Get the middleware the job should pass through.
 *
 * @return array<int, object>
 */
public function middleware(): array
{
    return [(new ThrottlesExceptions(10, 10 * 60))->when(
        fn (Throwable $throwable) => $throwable instanceof HttpClientException
    )];
}

На відміну від методу when, який повертає завдання назад у чергу або викидає виняток, метод deleteWhen дозволяє повністю видалити завдання, коли виникає певний виняток:

use App\Exceptions\CustomerDeletedException;
use Illuminate\Queue\Middleware\ThrottlesExceptions;

/**
 * Get the middleware the job should pass through.
 *
 * @return array<int, object>
 */
public function middleware(): array
{
    return [(new ThrottlesExceptions(2, 10 * 60))->deleteWhen(CustomerDeletedException::class)];
}

Якщо ви хочете, щоб винятки, до яких застосовано тротлінг, повідомлялися обробнику винятків вашого застосунку, ви можете зробити це, викликавши метод report під час прикріплення middleware до вашого завдання. За бажанням ви можете передати замикання в метод report, і виняток буде повідомлено лише в разі, якщо задане замикання повертає true:

use Illuminate\Http\Client\HttpClientException;
use Illuminate\Queue\Middleware\ThrottlesExceptions;

/**
 * Get the middleware the job should pass through.
 *
 * @return array<int, object>
 */
public function middleware(): array
{
    return [(new ThrottlesExceptions(10, 10 * 60))->report(
        fn (Throwable $throwable) => $throwable instanceof HttpClientException
    )];
}

Тротлінг винятків із Redis

Якщо ви використовуєте Redis, ви можете скористатися middleware Illuminate\Queue\Middleware\ThrottlesExceptionsWithRedis, який точно налаштований під Redis і ефективніший за базовий middleware тротлінгу винятків:

use Illuminate\Queue\Middleware\ThrottlesExceptionsWithRedis;

public function middleware(): array
{
    return [new ThrottlesExceptionsWithRedis(10, 10 * 60)];
}

Метод connection можна використовувати, щоб указати, яке зʼєднання Redis має використовувати middleware:

return [(new ThrottlesExceptionsWithRedis(10, 10 * 60))->connection('limiter')];

Повернення завдань у чергу

Middleware Release дозволяє повернути завдання назад у чергу без його виконання. Метод Release::when поверне завдання в чергу, якщо задана умова обчислюється як true, а метод Release::unless поверне завдання в чергу, якщо умова обчислюється як false:

use Illuminate\Queue\Middleware\Release;

/**
 * Get the middleware the job should pass through.
 */
public function middleware(): array
{
    return [
        Release::when($condition, releaseAfter: 60),
    ];
}

Повернення завдання назад у чергу все одно збільшуватиме загальну кількість спроб завдання. Ви можете відповідно налаштувати атрибути Tries і MaxExceptions у вашому класі завдання.

Ви також можете передати Closure у методи when і unless для складнішого обчислення умов:

use Illuminate\Queue\Middleware\Release;

/**
 * Get the middleware the job should pass through.
 */
public function middleware(): array
{
    return [
        Release::when(function (): bool {
            return ! $this->order->isPaid();
        }, releaseAfter: 60),
    ];
}

Пропуск завдань

Middleware Skip дозволяє вказати, що завдання слід пропустити / видалити без потреби змінювати логіку самого завдання. Метод Skip::when видалить завдання, якщо задана умова обчислюється як true, а метод Skip::unless видалить завдання, якщо умова обчислюється як false:

use Illuminate\Queue\Middleware\Skip;

/**
 * Get the middleware the job should pass through.
 */
public function middleware(): array
{
    return [
        Skip::when($condition),
    ];
}

Ви також можете передати Closure у методи when і unless для складнішого обчислення умов:

use Illuminate\Queue\Middleware\Skip;

/**
 * Get the middleware the job should pass through.
 */
public function middleware(): array
{
    return [
        Skip::when(function (): bool {
            return $this->shouldSkip();
        }),
    ];
}

Диспетчеризація завдань

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

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use App\Models\Podcast;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     */
    public function store(Request $request): RedirectResponse
    {
        $podcast = Podcast::create(/* ... */);

        // ...

        ProcessPodcast::dispatch($podcast);

        return redirect('/podcasts');
    }
}

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

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

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

У нових застосунках Laravel зʼєднання database визначено як чергу за замовчуванням. Ви можете вказати інше зʼєднання черги за замовчуванням, змінивши змінну середовища QUEUE_CONNECTION у файлі .env вашого застосунку.

Відкладена диспетчеризація

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

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use App\Models\Podcast;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     */
    public function store(Request $request): RedirectResponse
    {
        $podcast = Podcast::create(/* ... */);

        // ...

        ProcessPodcast::dispatch($podcast)
            ->delay(now()->plus(minutes: 10));

        return redirect('/podcasts');
    }
}

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

ProcessPodcast::dispatch($podcast)->withoutDelay();

Попередження. Сервіс черг Amazon SQS має максимальний час затримки 15 хвилин.

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

Synchronous Dispatching, Bulk Dispatching, Preparing Jobs Before Dispatch, Jobs & Database Transactions, Job Chaining, Customizing The Queue and Connection, Specifying Max Job Attempts / Timeout Values, SQS FIFO and Fair Queues, Queue Failover, Error Handling, Job Batching (Defining Batchable Jobs, Dispatching Batches, Chains and Batches, Adding Jobs to Batches, Inspecting Batches, Cancelling Batches, Batch Failures, Pruning Batches, Storing Batches in DynamoDB), Queueing Closures, Running the Queue Worker (The queue:work Command, Queue Priorities, Queue Workers and Deployment, Reacting to Worker Signals, Job Expirations and Timeouts, Pausing and Resuming Queue Workers), Supervisor Configuration, Dealing With Failed Jobs (Cleaning Up After Failed Jobs, Retrying Failed Jobs, Ignoring Missing Models, Pruning Failed Jobs, Storing Failed Jobs in DynamoDB, Disabling Failed Job Storage, Failed Job Events), Clearing Jobs From Queues, Monitoring Your Queues, Testing (Faking a Subset of Jobs, Testing Job Chains, Testing Job Batches, Testing Job / Queue Interactions), Job Events.

ЯК ЦЯ СТОРІНКА ВИГЛЯДАЄ В ПОШУКУ
phpukraine.com/docs/laravel/queues
Черги — Laravel документація українською
Черги у Laravel 13.x: переклад офіційної документації українською. Оновлено 4 вересня 2026. Приклади коду, пояснення та посилання на питання зі співбесід.
Переклад робить спільнота

Виправити терміни, дописати розділ або взяти нову главу може кожен. Термінологію узгоджуємо в глосарії, щоб переклад лишався однорідним.

1
Перекладачів
90%
Готовності
0
Вільних розділів
Глосарій термінів