awesome-everything EN
↑ Обратно к восхождению

Архитектура бэкенда

Graceful shutdown: чтение кода и конфигурации

Суть Читай реальные обработчики shutdown, манифест пода Kubernetes и последовательность drain, предсказывай сбой и выбирай самое рычажное исправление, которое senior сделает первым.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min

Баги shutdown прячутся в коде обработчика и манифесте пода, а не в прозе. Прочитай каждый сниппет, предскажи, где именно он теряет запрос, и выбери исправление, к которому senior потянется первым.

Цель

Отработай цикл, который ты проходишь в каждом ревью shutdown: проследи сигнал, порядок и дедлайн через реальный код и конфиг, затем найди единственное изменение, останавливающее потерю запросов.

Сниппет 1 — обработчик SIGTERM

const server = app.listen(8080);

process.on("SIGTERM", () => {
  server.close(() => {
    db.end();
    process.exit(0);
  });
});
Викторина

Под реальной нагрузкой этот обработчик периодически зависает до SIGKILL, даже когда ни один запрос активно не выполняется. В чём дефект и исправление?

Сниппет 2 — порядок drain

process.on("SIGTERM", async () => {
  setReadiness(false);              // провалить readiness probe
  await db.end();                   // закрыть пул БД
  await redis.quit();               // закрыть кэш
  await closeHttpServer(server);    // drain + закрыть HTTP последним
  process.exit(0);
});
Викторина

Этот обработчик корректно проваливает readiness, но in-flight запросы всё равно падают с ошибками pool-closed и cache-closed во время drain. Что не так?

Сниппет 3 — манифест пода

spec:
  terminationGracePeriodSeconds: 30
  containers:
  - name: api
    lifecycle:
      preStop:
        exec:
          command: ["sleep", "5"]
    readinessProbe:
      httpGet: { path: /ready, port: 8080 }
    livenessProbe:
      httpGet: { path: /ready, port: 8080 }
Викторина

preStop sleep и grace period выглядят нормально, но во время shutdown поды иногда убиваются и перезапускаются посреди drain. Что в этом манифесте это вызывает?

Сниппет 4 — guardian timeout и requeue

process.on("SIGTERM", async () => {
  worker.stopPulling();             // прекратить брать новые задачи
  const t = setTimeout(() => {
    log.error("drain timed out, forcing exit");
    process.exit(1);
  }, 25_000);                       // guardian < grace period
  await worker.finishOrRequeue();   // ack завершённых, requeue остальных
  clearTimeout(t);
  process.exit(0);
});
Викторина

Guardian timeout и логика requeue структурно корректны. Какое единственное оставшееся предусловие делает worker.finishOrRequeue() безопасным и что ломается без него?

Итог

Каждый баг shutdown читается в обработчике и манифесте: один server.close() зависает на простаивающих keep-alive сокетах, поэтому закрывай их явно; teardown должен идти в reverse dependency order с datastores последними, иначе in-flight queries бьются в мёртвый пул; liveness и readiness не должны делить эндпоинт, иначе провал readiness для drain заодно триггерит перезапуск; а guardian timeout покупает чистый выход на своих условиях, пока requeue остаётся корректным только при идемпотентном consumer. Проследи сигнал, порядок и дедлайн через код, исправь единственную строку, теряющую запрос, и перепроверь под нагрузкой.

Продолжить восхождение ↑Graceful shutdown: ноль потерянных запросов на деплое
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.