0% прочитано

Laravel Supervisor: SSR, обробник черги та Reverb на одному production-сервері

У production ICanUp одночасно працюють кілька довготривалих процесів: Laravel queue worker, Reverb і Inertia SSR. Я використовую Supervisor не просто для запуску команд, а як єдиний контракт керування процесами: автоматичний запуск, перезапуск після збою, окремі журнали, контроль стану та передбачувана поведінка після deployment.

15 вересня 2026 р. 10 хв читанняDevOps

Коли в ICanUp з'явилися Reverb, фонові задачі та Inertia SSR, одного PHP-FPM уже було недостатньо для всього production-застосунку.

На сервері одночасно повинні постійно працювати три окремі процеси: обробник черги, Reverb і SSR.

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

Саме тому я використовую Supervisor не як зручну команду запуску, а як єдиний контракт керування довготривалими процесами застосунку.

Supervisor відповідає за життєвий цикл процесу: запуск, повторний запуск після збою, зупинку, журнали та стан. Але статус RUNNING ще не доводить, що сам сервіс функціонально працює правильно.
Laravel production server with Supervisor managing queue worker, Reverb and Inertia SSR as separate long-running processes
Один production-сервер, але три різні довготривалі процеси. Supervisor керує їхнім життєвим циклом, а кожен сервіс потребує власної перевірки працездатності.

Один Laravel-застосунок не означає один процес

HTTP-запити в моєму production-середовищі обробляє PHP-FPM. Але частина функціональності живе поза звичайним HTTP request-response циклом.

Черга повинна обробляти фонові задачі. Reverb повинен постійно приймати WebSocket-з'єднання. SSR повинен бути готовим серверно рендерити Inertia-сторінки.

Це різні процеси з різними командами, помилками та способом перевірки.

Процес

За що відповідає

Що помітить користувач при збої

Laravel queue worker

Фонові задачі

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

Reverb

WebSocket та realtime-події

HTTP працює, але живі оновлення перестають приходити

Inertia SSR

Серверний рендеринг Vue/Inertia

Звичайна сторінка може ще відкриватися, але SSR або SEO-відповідь працює неправильно

Саме це робить проблему неочевидною

Якщо падає PHP-FPM, проблема очевидна: HTTP-запити перестають нормально оброблятися.

З довготривалими процесами все складніше.

Зупинений обробник черги може кілька хвилин або годин залишатися непомітним. Reverb може не працювати, хоча звичайна навігація сайтом справна. SSR може падати лише на конкретній сторінці або конкретному сценарії.

Тому "сайт повертає 200" і "всі процеси застосунку справні" - це різні твердження.

У production я маю три окремі Supervisor programs

У поточному production-середовищі ICanUp Supervisor керує окремими процесами для worker, Reverb та SSR.

Їхні імена навмисно різні, щоб кожен сервіс можна було перевірити або перезапустити незалежно.

Production processes
icanup-worker:icanup-worker_00icanup-reverbicanup-ssr

Це важлива деталь. Я не хочу перезапускати весь application stack лише тому, що потрібно оновити один процес.

Перша команда після deployment - перевірити фактичний стан

BASH - Перевірити всі процеси Supervisor
sudo supervisorctl status

Я очікую побачити потрібні процеси у стані RUNNING.

Але це лише перший рівень перевірки.

Очікуваний загальний стан
icanup-worker:icanup-worker_00   RUNNINGicanup-reverb                    RUNNINGicanup-ssr                       RUNNING

RUNNING означає лише те, що процес не завершився

Supervisor добре відповідає на питання: "Чи живий процес?"

Але він не завжди може відповісти на питання: "Чи виконує цей процес свою роботу правильно?"

Supervisor показує

Але окремо потрібно перевірити

worker = RUNNING

Чи справді обробляються задачі черги

Reverb = RUNNING

Чи слухається потрібний порт і працюють WebSocket-з'єднання

SSR = RUNNING

Чи реальна сторінка успішно проходить серверний рендеринг

Supervisor є менеджером процесів, а не повною системою перевірки працездатності застосунку. Process status і service health не потрібно змішувати.

Обробник черги є довготривалим PHP-процесом

Laravel queue worker не завершується після одного завдання. Він залишається в пам'яті та чекає наступної роботи.

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

BASH - Попросити Laravel workers завершитися коректно
php artisan queue:restart

queue:restart дає workers сигнал завершитися після поточної роботи. Після цього Supervisor запускає процес знову.

У deployment я також можу явно перевірити або перезапустити Supervisor group.

BASH - Перезапустити production workers
sudo supervisorctl restart icanup-worker:*

Reverb живе окремо від HTTP-запитів

Reverb підтримує довготривалі WebSocket-з'єднання.

Його збій не обов'язково вплине на звичайний HTTP request. Користувач може відкрити сторінку, але realtime-функції вже не працюватимуть.

Саме тому Reverb має власний Supervisor program.

BASH - Перезапустити Reverb
sudo supervisorctl restart icanup-reverb

Після перезапуску я перевіряю не тільки Supervisor status, а й те, що сервер слухає очікувані порти.

BASH - Перевірити listening ports
ss -lnt
У статті я не прив'язую перевірку до конкретного номера Reverb port. Він є частиною environment configuration і повинен перевірятися з поточних production settings.

SSR теж повинен бути постійно запущеним

Після підключення Inertia SSR у мене з'явився ще один довготривалий процес.

Його задача - приймати запити від Laravel та повертати серверно відрендерений HTML для Inertia-сторінок.

Якщо процес SSR зупиниться або почне падати, це може проявитися не так очевидно, як повний HTTP outage.

BASH - Перезапустити SSR
sudo supervisorctl restart icanup-ssr

Окремо я перевіряю реальний HTML сторінки. Саме так свого часу в ICanUp було видно різницю між метатегами, які зʼявлялися лише в браузері, та метатегами у початковій SSR-відповіді.

Цей випадок я окремо описала у матеріалі про Inertia SSR і метатеги в початковому HTML.

BASH - Перевірити SSR у реальній HTTP-відповіді
curl -s https://icanup.com.ua/ \  | grep -E '<title>|og:title'

Кожен процес має запускатися окремо

Я не обʼєдную worker, Reverb та SSR в один shell script, який Supervisor бачить як один process.

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

Окремий процес для кожної ролі
Supervisor|+-- icanup-worker|+-- icanup-reverb|+-- icanup-ssr

Конфігурація має описувати життєвий цикл, а не тільки команду

Для мене Supervisor configuration - це не просто command=....

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

INI - Скорочений контракт довготривалого процесу
[program:example-process]directory=/var/www/icanupcommand=<process-command>user=deploy autostart=trueautorestart=true startsecs=5stopsignal=TERMstopasgroup=truekillasgroup=true redirect_stderr=truestdout_logfile=<process-log>
Це скорочений приклад контракту, а не буквальна копія production config. Конкретні команди й log paths залежать від ролі process.

Чому я використовую autorestart

Довготривалий процес може завершитися не тільки під час deployment.

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

autorestart=true дозволяє Supervisor повторно запустити процес без ручного втручання.

Але нескінченний restart loop не є виправленням причини. Якщо process постійно падає, потрібні його журнали і окрема діагностика.

Правильний користувач процесу важливий не менше за команду

У моєму production-середовищі довготривалі CLI/SSR процеси можуть працювати від користувача deploy, тоді як HTTP через PHP-FPM обробляє www-data.

Це окремий системний контракт прав доступу.

Я не запускаю application processes від root лише для того, щоб обійти permission problem.

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

Після зміни Supervisor config недостатньо просто restart

Коли змінюється саме Supervisor configuration, спочатку потрібно попросити Supervisor перечитати її.

BASH - Застосувати змінену конфігурацію
sudo supervisorctl rereadsudo supervisorctl updatesudo supervisorctl status

reread знаходить зміни у configuration files, а update застосовує новий набір programs.

Це відрізняється від звичайного restart уже відомого process.

Після deployment довготривалі процеси мають отримати новий код

Одна з найважливіших практичних причин керувати цими процесами через Supervisor - deployment.

Після оновлення Git revision, Composer dependencies, frontend build або environment configuration старий process може залишатися в памʼяті зі старим станом.

Тому deployment не завершується на оновленні файлів.

Що відбувається після оновлення коду
Deploy new code      |      vRebuild dependencies / caches      |      vRestart long-running processes      |      +-- Queue worker      +-- Reverb      +-- SSR      |      vVerify process state      |      vVerify real service behavior

Мій порядок після deployment

  • Оновити application code та dependencies.
  • Виконати migrations і перебудувати Laravel caches.
  • Попросити Laravel queue workers завершитися коректно.
  • Перезапустити worker group під Supervisor.
  • Перезапустити Reverb.
  • Перезапустити SSR.
  • Перевірити supervisorctl status.
  • Перевірити listening ports для потрібних мережевих процесів.
  • Перевірити реальний HTTP та SSR output.
  • Лише після цього вважати deployment успішним.

Це продовження CI/CD, а не окрема ручна процедура

Я не хочу памʼятати ці кроки щоразу вручну.

У ICanUp перезапуск і перевірка довготривалих процесів є частиною deployment flow.

Більший контекст цього процесу я описувала у матеріалі про реальний Laravel CI/CD pipeline.

Не всі три процеси потрібно масштабувати однаково

Queue worker природно може мати кілька processes, якщо кількість задач зростає.

Для цього Supervisor підтримує групи та кілька екземплярів одного program.

Reverb і SSR на одному сервері мають іншу модель. Без окремої архітектурної причини я не запускаю випадкові дублікати процесів, які конкурують за той самий port або endpoint.

Не потрібно вручну запускати другий Reverb або SSR поверх process, яким уже керує Supervisor. Спочатку перевіряю supervisorctl status і лише потім вирішую, чи потрібен restart.

Окремі журнали значно спрощують діагностику

Якщо worker, Reverb та SSR пишуть усе в один загальний process log, під час збою доводиться спочатку визначати, до якого сервісу належить повідомлення.

Окремі журнали дають простіший звʼ™язок:

Окремі журнали за роллю процесу
worker failure -> worker logReverb failure -> Reverb logSSR failure -> SSR log

При цьому application logging Laravel залишається окремим рівнем. Supervisor logs і Laravel logs відповідають на різні питання.

Що я перевіряю, якщо process постійно перезапускається

  • Команду Supervisor і робочу директорію.
  • Користувача, від якого запускається process.
  • Environment variables, доступні цьому process.
  • Права доступу до потрібних файлів і каталогів.
  • Окремий process log.
  • Laravel log, якщо process завантажує Laravel.
  • Чи не зайнятий потрібний port іншим process.
  • Чи працює та сама команда вручну від того самого системного користувача.

Перевірка команди вручну має повторювати Supervisor context

Якщо команда працює в моєму SSH shell, це ще не гарантує, що вона працює під Supervisor.

Можуть відрізнятися user, working directory, environment та PATH.

Тому при діагностиці я намагаюся повторити саме той context, у якому Supervisor запускає process.

Команда, яка працює вручну, і процес, який Supervisor може стабільно підтримувати в production, - не завжди одне й те саме.

Supervisor не замінює перевірки працездатності

Я спеціально розділяю process supervision і health verification.

Supervisor повинен тримати процес запущеним. Deployment verification повинна довести, що цей процес виконує свою функцію.

Рівень

Приклад перевірки

Process

supervisorctl status

Network

Чи слухається потрібний port

Application

Чи виконується реальна задача або SSR render

Public behavior

Чи працює очікувана функція для користувача

Найгірший сценарій - тихий частковий збій

Для мене найнебезпечніший випадок - не повний outage, а ситуація, коли сайт виглядає працездатним лише частково.

HTTP відповідає, але queue worker стоїть. Сторінка відкривається, але realtime не працює. Браузер бачить контент, але SSR падає і початковий HTML неправильний.

Саме тому три довготривалі процеси повинні мати окреме керування і окремі перевірки.

Що я не роблю

  • Не запускаю worker, Reverb та SSR одним спільним shell process.
  • Не запускаю application processes від root заради зручності.
  • Не вважаю RUNNING достатнім доказом працездатності сервісу.
  • Не запускаю другий Reverb вручну, не перевіривши Supervisor.
  • Не залишаю довготривалі processes зі старим кодом після deployment.
  • Не змішую журнали всіх process roles в один потік без потреби.
  • Не перезапускаю весь server лише через збій одного application process.
  • Не перевіряю production тільки одним HTTP 200.

Мій короткий Supervisor checklist

  • Кожна довготривала роль має окремий Supervisor program.
  • Program має правильну working directory.
  • Process запускається від правильного системного користувача.
  • Увімкнено autostart і продумано autorestart.
  • Зупинка процесу коректно передає signal дочірнім processes.
  • Worker, Reverb і SSR мають окремі журнали.
  • Після зміни Supervisor config виконуються reread і update.
  • Після deployment довготривалі processes перезапускаються.
  • Після restart перевіряється supervisorctl status.
  • Після process check виконується окрема функціональна перевірка.

Що я залишила собі на майбутнє

  • Розділяти HTTP runtime і довготривалі processes.
  • Для worker, Reverb і SSR мати окремий життєвий цикл.
  • Не змішувати process status із service health.
  • Після deployment завжди оновлювати довготривалі processes.
  • Перевіряти Reverb не тільки за статусом process, а й за мережевою доступністю.
  • SSR перевіряти реальним HTML response.
  • Queue worker перевіряти не лише за RUNNING, а й за фактичним виконанням задач.
  • Не приховувати permission або environment problems запуском від root.
  • Зберігати процеси достатньо незалежними, щоб один збій не вимагав перезапуску всього application stack.

Висновок

На одному production-сервері ICanUp одночасно працюють різні частини одного Laravel-застосунку: PHP-FPM, queue worker, Reverb та Inertia SSR.

Supervisor дав мені один зрозумілий спосіб керувати трьома довготривалими процесами: запускати їх після reboot, перезапускати після збою, оновлювати після deployment і бачити їхній поточний стан.

Але найважливіший урок був іншим: керування процесом і перевірка його функціональності - це різні рівні.

Worker може бути RUNNING, але не виконувати потрібну роботу. Reverb може бути RUNNING, але realtime усе одно потребує окремої перевірки. SSR може бути RUNNING, але конкретна сторінка все одно може падати під час server rendering.

Тому мій production-контракт простий: Supervisor тримає processes живими, а deployment і health checks доводять, що вони справді виконують свою роботу.