Перейти до основного вмісту
Версія: 2.0

Поступові оновлення

Виконуйте поступове оновлення для заміни вузлів API, worker чи scheduler без вимкнення розгортання. Контракт охоплює невелику кластерну форму з посібника самостійного розгортання: два чи три вузли API за балансувальником, спільні зовнішні MySQL або PostgreSQL, спільний Redis, незалежно масштабовані worker та рівно один scheduler або runner обслуговування.

Поступове оновлення підтримується за виконання всіх гарантій цієї сторінки. Поза цими межами використовуйте задокументований процес оновлення із зупинкою всього розгортання.

Терміни ролей і маніфест форм цього контракту наведені в топології ролей Server. Цей посібник описує поступове оновлення поточних класів процесів standalone_server.

Що означає поступове оновлення​

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

Контракт розрізняє чотири класи процесів поточної форми standalone_server, кожен із власним підходом до оновлення:

  • Вузли HTTP/API: процеси Server без стану, що обслуговують HTTP і зараз містять ролі api_ingress, control_plane, matching і history_projection.
  • Worker: процеси SDK, що опитують площину worker та виконують завдання activity й workflow як execution_plane.
  • Scheduler / runner обслуговування: єдиний процес, що запускає розклади та забезпечує тайм-аути activity й зберігання історії як роль scheduler.
  • Bootstrap: одноразовий процес міграцій бази даних і створення типового простору імен.

Вузли API та worker оновлюються незалежно. Scheduler має один екземпляр: зупиніть старий перед запуском нового. Решта розгортання обслуговує трафік протягом цього проміжку.

Правила сумісного змішування версій​

Вікно співіснування — час, коли одночасно працюють кілька образів Server, версій пакета Workflow або версій SDK worker. У ньому мають виконуватися всі правила цього розділу.

Образ Server і пакет Workflow​

  • Лише сусідні версії. Під час поступового оновлення кожен вузол API та інший процес Server має використовувати образ Server, версія пакета Workflow якого має ту саму мажорну версію, що й попередній пакет кластера, і відрізняється від кожного іншого живого процесу щонайбільше на одну мінорну версію. Перехід через мажорну версію потребує оновлення із загальною зупинкою.
  • Міграції лише з додаванням. Кожна зміна схеми Durable Workflow v2 є додатковою в межах мажорної версії. Нові вузли не повинні потребувати стовпця чи таблиці, яких ще немає після міграцій. Старі вузли мають працювати з новим стовпцем, якого не читають. Це забезпечують правила порядку міграцій.
  • Сусідні версії площини керування й протоколу worker. Кожен вузол публікує підтримувані діапазони control_plane.version і worker_protocol.version через GET /api/cluster/info. Під час оновлення підтримуваний діапазон нового образу має перетинатися з діапазоном кожного живого старого вузла. Виявіть діапазон перед оновленням і припиніть його за відсутності перетину.

SDK worker та ідентичність збірки​

  • Worker позначають кожну збірку. Кожен worker поступового оновлення має реєструватися через POST /api/worker/register зі стабільним build_id. Група без версії (build_id: null) є типовою до оновлення. Посібник оновлення build ID worker пояснює перший перехід.
  • Fingerprint визначення workflow залишаються закріпленими. Образи Server із DW_V2_PIN_TO_RECORDED_FINGERPRINT=true, типовим значенням, закріплюють незавершені run за fingerprint визначення workflow, записаним у WorkflowStarted. Новий worker з іншим fingerprint того самого workflow відмовляється забирати ці run до їх завершення.
  • Підхід до допуску збірок, що співіснують. Оберіть DW_V2_FLEET_VALIDATION_MODE перед початком. warn дозволяє оновлення навіть без живого worker потрібного маркера сумісності. fail блокує диспетчеризацію та закриває допуск контракту готовності в цьому вікні. Виробничі оновлення, що потребують чистого переходу, мають використовувати fail.

Порядок схеми й bootstrap​

Зміни схеми виконуються одним проходом bootstrap. Порядок важливий.

  1. Спочатку виконайте bootstrap рівно один раз. Виконайте php artisan server:bootstrap --force або еквівалент опублікованого образу з одного контейнера перед запуском будь-якого нового вузла API, worker чи scheduler. Bootstrap виконує migrate і створення типового простору імен. Він приймає міграції пакета Workflow, таблиці яких уже існують на підключенні.
  2. Нова схема має бути сумісною зі старим кодом. Кожна міграція v2 цього шляху лише додає таблиці, стовпці чи індекси. Старі вузли API й worker продовжують працювати з новою схемою.
  3. Не запускайте новий код до завершення bootstrap. Оновлюйте образ Server лише після успішного завершення bootstrap. Нові вузли API й worker можуть залежати від щойно створених таблиць. Запуск до завершення bootstrap є найпоширенішою причиною сплеску 5xx під час переходу.
  4. Bootstrap ідемпотентний. Його безпечно повторювати. Якщо він частково завершився помилкою, виправте причину й повторіть. Журнал міграцій продовжує з місця зупинки, а створення простору імен нічого не змінює за наявності рядка.

Міграція, що з’явилася на одному сервері раніше за інший, НЕ ПОВИННА порушувати інтерфейс готовності. Якщо під час планування знайдено зміну, яка не є додатковою, використовуйте вікно загальної зупинки для цього випуску й поверніться до поступових оновлень у наступному.

Drain і допуск у вікні співіснування​

Три інтерфейси допуску автоматично забезпечують безпеку співіснування:

  • Допуск запуску. Кожен процес Server завантажує BackendCapabilities, LongPollCacheValidator, WorkflowModeGuard і контракт готовності під час запуску. Процес із backend чи кешем, що не відповідає контракту v2, відмовляється позначати себе готовим.
  • Сумісність worker. За DW_V2_FLEET_VALIDATION_MODE=fail і відсутності живого worker потрібного маркера сумісності в області підключення та черги завдання роль matching блокує диспетчеризацію, а перевірка здоров’я worker_compatibility переходить із warning до error. Завдання залишаються готовими й видимими та не втрачаються. Контракт готовності повертає 503 на цьому вузлі, щоб балансувальник виключив його з обслуговування.
  • Безпека маршрутизації. Готове завдання без живого worker потрібної сумісності зберігається й рахується в метриці backlog compatibility_blocked_runs. Drain маршрутизації не призводить до прихованої втрати завдань. Гарантія виконання щонайменше один раз залишається чинною.

Щоб скоротити вікно співіснування worker, переведіть старі групи в drain після появи нових. Використовуйте процес оновлення build ID worker:

dw task-queue:drain orders-critical --build-id orders-worker-2026-04-21-z9

drain_intent групи стає draining. Worker цієї збірки завершують поточну роботу, але припиняють забирати нові завдання. Дочекайтеся нуля active_worker_count і draining_worker_count перед зупинкою старих процесів worker.

Scheduler не має довготривалої черги завдань і не потребує drain worker. Зупиніть старий контейнер scheduler, виконайте bootstrap, якщо його ще не виконано, і запустіть новий. Вікно між ними обмежене часом запуску нового контейнера. Розклади відновлюються зі збереженого стану на наступному tick.

Якщо оновлення також вводить окреме розгортання ролі matching, явно задайте зміну топології. Не припускайте, що кожен вузол виконання продовжить загальний пошук готових завдань. У зіставленні й диспетчеризації завдань наведена форма workflow:v2:repair-pass --loop разом із DW_V2_MATCHING_ROLE_QUEUE_WAKE=0. Перевірте живий контракт вузла через GET /api/cluster/info: topology.current_shape має відповідати розгортанню переходу, topology.current_roles — задокументованому набору ролей вузла, а topology.matching_role.queue_wake_enabled, topology.matching_role.shape і topology.matching_role.wake_owner мають показувати очікуваного власника загального пошуку готових завдань. Типова форма повідомляє queue_wake_enabled: true, shape: "in_worker" і wake_owner: "worker_loop". Окремі розгортання matching змінюють вузли виконання на queue_wake_enabled: false, shape: "dedicated" і wake_owner: "dedicated_repair_pass".

Готовність і перемикання​

Визначайте допуск трафіку на вузол за контрактом готовності:

  • GET /api/health доводить обслуговування HTTP процесом.
  • GET /api/ready доводить доступ до налаштованих залежностей runtime, включно з міграціями, типовим простором імен та перевіркою допуску сумісності worker за DW_V2_FLEET_VALIDATION_MODE=fail.
  • GET /api/cluster/info доводить можливість автентифікованого клієнта виявити ідентичність збірки, протоколи площини керування й worker, кодеки payload та можливості Server.
  • POST /api/worker/register доводить можливість автентифікації worker в очікуваному просторі імен і черзі завдань.

Послідовність перемикання одного вузла API:

  1. Виключіть вузол із ротації балансувальника. Найпростіший шлях — спричинити невдачу перевірки готовності балансувальника, зупинивши pre-start hook нового образу перед запуском нового контейнера.
  2. Дочекайтеся завершення поточних запитів HTTP. Більшість клієнтів повторює запит після скидання підключення. Довгі підключення, як long-poll worker, підключаються до решти набору вузлів.
  3. Зупиніть старий контейнер і запустіть новий.
  4. Дочекайтеся 200 від GET /api/ready та нової ідентичності збірки в GET /api/cluster/info. За зміни топології matching також підтвердьте відповідність topology.matching_role.task_dispatch_mode, topology.matching_role.queue_wake_enabled, topology.matching_role.shape, topology.matching_role.wake_owner, topology.matching_role.partition_primitives і topology.matching_role.backpressure_model потрібному розгортанню перед поверненням трафіку. Використовуйте /api/system/operator-metrics для того самого локального контракту ролі matching разом із живими лічильниками backlog, відновлення й worker процесу, що відповідає.
  5. Поверніть вузол до ротації.

Повторюйте по одному вузлу. Не оновлюйте наступний, доки попередній не повернувся до ротації й не обслуговує трафік без помилок.

Worker перемикаються за групами:

  1. Запустіть нову групу worker із новим build_id.
  2. Підтвердьте rollout_status: "active" і ненульовий active_worker_count обох груп у dw task-queue:build-ids <queue> --json.
  3. Переведіть стару групу в drain через dw task-queue:drain.
  4. Дочекайтеся нуля active_worker_count і draining_worker_count старої групи.
  5. Зупиніть старі процеси worker.

Відкат​

Кожен крок оборотний. Сплануйте відкат перед початком.

  • Відкат bootstrap. Міграції v2 оборотні через стандартний шлях Laravel down(). Відкат міграції, потрібної новому образу, вимагає спочатку зупинити всі нові вузли. Інакше новий код бачить відсутній стовпець, а контракт готовності повертає 503. Більшість відкатів не потребує скасування міграцій, оскільки зміни схеми додаткові.

  • Відкат вузла API. Зупиніть новий контейнер і запустіть старий на тому самому вузлі. Виключіть вузол із ротації на час запуску та поверніть після успішного GET /api/ready. Повторіть для інших оновлених вузлів API. Старий код читає нову схему, бо зміна додаткова.

  • Відкат worker. Відновіть раніше спорожнену групу, переведіть невдалу групу в drain і знову масштабуйте відому робочу збірку:

    dw task-queue:resume orders-critical --build-id orders-worker-2026-04-21-z9
    dw task-queue:drain orders-critical --build-id orders-worker-2026-04-22

    Resume очищає drain_intent і drained_at. Worker, що надсилає heartbeat із відновленим build_id, повертається до active на наступному опитуванні. Обидва виклики ідемпотентні.

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

Перевірка оператором​

Перевіряйте кожен етап оновлення за інтерфейсами оператора.

ПитанняІнтерфейс
Чи bootstrap завершений?Код завершення 0 php artisan server:bootstrap --force. migrate:status показує виконання всіх міграцій.
Чи новий вузол готовий?GET /api/ready повертає 200, GET /api/cluster/info повідомляє нову збірку.
Чи здоровий допуск сумісності?workers.fleet, workers.active_workers і workers.active_workers_supporting_required у GET /api/system/operator-metrics погоджені щодо ненульової кількості worker кожного потрібного маркера сумісності.
Чи просувається drain worker?dw task-queue:build-ids <queue> --json показує зменшення active_worker_count і draining_worker_count групи drain.
Чи маршрутизація безпечна?backlog.compatibility_blocked_runs і backlog.max_compatibility_blocked_age_ms у GET /api/system/operator-metrics близькі до нуля, перевірка worker_compatibility не має error.
Чи scheduler наздогнав розклад?schedules.missed у GET /api/system/operator-metrics дорівнює нулю, schedules.oldest_overdue_at — null.
Чи накопичуються застряглі run?runs.repair_needed і runs.max_repair_needed_age_ms у GET /api/system/operator-metrics залишаються близькими до базових значень перед оновленням.

dw system:operator-metrics --json надає той самий знімок метрик оператора в консолі набору окремого Server, тож оператори можуть обрати зручний для свого процесу інтерфейс. Окрема служба Waterline може читати той самий стан оновлення Server через PHP SDK у /waterline/api/v2/health і /waterline/api/stats. Узгодьте її endpoint, простір імен та токен Server з оновлюваним набором. Вбудовані Laravel-розгортання надають ці маршрути Waterline зі свого пакета в процесі. Server API та CLI залишаються доступними в обох випадках, як описано в операційних межах оператора.

Сценарії помилок і дії​

СимптомІмовірна причинаДія
Новий вузол API не проходить GET /api/ready після запускуBootstrap не завершений або задано DW_V2_FLEET_VALIDATION_MODE=fail без живого сумісного workerПовторіть bootstrap. Запустіть сумісну групу worker перед поверненням вузла API до ротації.
worker_compatibility переходить до error під час оновленняПотрібний маркер сумісності не має живого worker із підтримкоюЗапустіть більше worker підтримуваного build_id. Відновіть раніше спорожнену групу, якщо потрібен відкат.
backlog.compatibility_blocked_runs і max_compatibility_blocked_age_ms зростаютьЗавдання очікують маркер, якого не підтримує живий workerТа сама дія. Завдання зберігаються й автоматично надсилаються після heartbeat сумісного worker.
dw task-queue:drain успішний, але worker продовжують забирати завданняПроцес worker не надсилав heartbeat після drainДочекайтеся одного циклу heartbeat. Якщо група залишається активною, перезапустіть процес worker, щоб отримати намір drain.
Запуски розкладів припинилися після перезапуску schedulerСтарий і новий scheduler зупиненіЗапустіть новий контейнер scheduler. Перевірте повернення schedules.missed до нуля під час наступного зчитування метрик оператора.

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