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

Чому розгортання «вбивали» завдання

Коли з'являється нова версія, менеджери процесів, такі як Supervisor, Docker та Kubernetes, наказують існуючим воркерам зупинитися, надсилаючи SIGTERM — ввічливий запит на завершення. Більшість воркерів чекають на завершення поточного завдання перед виходом. Проблема виникає, коли менеджер надає лише кілька секунд на виконання запиту. Якщо завдання потребує хвилин, менеджер переходить до SIGKILL, миттєво вбиваючи процес. Завдання так і не досягає стабільного стану, залишаючи частково оновлені записи, «сирітські» файли або дубльовану роботу.

Відповідь Laravel: кооперативне переривання

Laravel 13.31 вводить контракт під назвою Interruptible, який клас завдання може реалізувати, щоб дізнаватися про запит на завершення. Коли надходить SIGTERM, Laravel викликає метод завдання interrupted(). Фреймворк не зупиняє завдання автоматично; завдання має самостійно перевірити прапорець, який встановлює Laravel, і завершити роботу. Ця модель співпраці дозволяє розробникам завершити поточну ітерацію циклу, відкотити часткові зміни або записати контрольну точку перед виходом.

Як зробити завдання переривним

  1. Реалізуйте контракт — додайте implements Interruptible до визначення класу завдання.
  2. Перевіряйте прапорець у циклі обробки — вставляйте перевірку на кожній ітерації, щоб побачити, чи має завдання зупинитися.
  3. Виконайте очищення — у методі interrupted() збережіть будь-який стан, який дозволить завданням продовжити роботу пізніше, або залогуйте переривання для подальшого аналізу.

Найбільша пастка: не використовуйте --once

Запуск воркера черги з параметром php artisan queue:work --once повністю вимикає обробку сигналів. Воркер обробляє одне завдання і виходить, але він ніколи не реєструє обробник SIGTERM. Як наслідок, будь-яке переривне завдання ігнорує запит на завершення і вбивається посеред процесу. Така модель зустрічається в контейнерах, що керуються cron, та при одноразових розгортаннях. Виправте це, запускаючи режим демона (php artisan queue:work) щоразу, коли вам потрібні переривні завдання.

Відстеження переривань

Laravel генерує дві події, до яких ви можете підключитися:

  • WorkerInterrupted — генерується щоразу, коли будь-який воркер отримує SIGTERM. Логування цієї події дає загальне уявлення про те, як часто розгортання перериває воркерів.
  • JobInterrupted — генерується лише в тому випадку, якщо поточне завдання реалізує контракт Interruptible. Використовуйте цю подію для запуску специфічного для завдання очищення, наприклад, видалення тимчасових файлів або оновлення маркера «останнього обробленого рядка».

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

Оновлення звітності про розмір черги

Реліз додає метод totalSize() до менеджера черг, який повертає загальну кількість очікуваних завдань у всіх чергах. Це значення є надійним для драйверів на базі бази даних та Redis, які повідомляють фактичну кількість. Драйвери на кшталт SQS, Sync та Beanstalkd все ще повертають нуль, оскільки вони не надають підрахунок через API Laravel. Командам, які використовують SQS, слід продовжувати покладатися на метрики CloudWatch для визначення глибини черги.

Що це означає для різних конфігурацій

  • Docker/Kubernetes — період коректного завершення роботи тепер можна використовувати ефективно. Збільште період очікування завершення (termination grace period), щоб у завдань було кілька секунд на те, щоб помітити прапорець і чисто вийти.
  • Supervisor — встановіть stopwaitsecs вищим за час, за який, як ви очікуєте, завдання завершиться після отримання прапорця переривання.
  • Застарілі завдання — перегляньте будь-яке завдання, яке працює довше за таймаут менеджера, і, де це можливо, зробіть його переривним.

Контраргумент: додаткова складність

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

Контрольний список дій

  1. Проскануйте скрипти розгортання на наявність прапорця --once і замініть його на режим демона (daemon mode), де використовуються переривні завдання.
  2. Визначте завдання, що тривають найдовше (ті, що обробляють десятки тисяч рядків або виконуються кілька хвилин), і додайте контракт Interruptible.
  3. Вставте перевірку прапорця всередині кожної ітерації циклу та перенесіть увесь необхідний код завершення у метод interrupted().
  4. Підключіть слухачів до WorkerInterrupted та JobInterrupted, щоб збирати метрики про те, як часто розгортання впливають на обробку.
  5. Для черг Redis або баз даних використовуйте totalSize() для моніторингу черги (backlog); для SQS залиште налаштовані сповіщення CloudWatch.

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