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

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

Жизненный цикл запроса: чтение кода

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

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

Цель

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

Сниппет 1 — цепочка middleware

const app = express();

app.use(express.json());                 // парсер тела, без лимита размера
app.post("/admin/wipe", wipeHandler);     // <-- зарегистрирован здесь
app.use(rateLimit({ max: 100 }));         // rate limiter
app.use(requireAuth);                     // auth: 401 без валидного токена
app.use(errorHandler);                    // ловит throw'ы ниже по цепочке
Викторина

Какие проблемы создаёт этот порядок регистрации и каков фикс?

Сниппет 2 — стриминговый экспорт

function exportCSV(rows, res) {
  res.setHeader("Transfer-Encoding", "chunked");
  for (const row of rows) {
    res.write(toCSVLine(row));   // возвращаемое значение игнорируется
  }
  res.end();
}
Викторина

Это проходит все тесты, но даёт OOM в production на одном медленном клиенте. В чём баг и каков корректный переписанный вариант?

Сниппет 3 — построитель ответа

app.get("/orders", async (req, res) => {
  const orders = await db.query("SELECT * FROM orders"); // без лимита
  res.status(200).json({ ok: true, data: orders });      // JSON.stringify
});
Викторина

По мере роста таблицы orders этот эндпоинт деградирует и иногда стопорит все остальные запросы. Какие две остановки жизненного цикла виноваты и каков фикс?

Сниппет 4 — deadline, который не пробрасывается

async function getProfile(userId) {
  // каждый клиент ставит свой фиксированный таймаут 1с; ничего не пробрасывается
  const user = await usersClient.get(userId, { timeoutMs: 1000 });
  const prefs = await prefsClient.get(userId, { timeoutMs: 1000 });
  const feed = await feedClient.get(userId, { timeoutMs: 1000 });
  return { user, prefs, feed };
}
Викторина

Точка входа обещает SLA 1 с, но эта функция может занять ~3 с, когда downstream'ы медленные. Почему и какая форма корректна?

Итог

Каждый инцидент жизненного цикла читается в проводке или на горячем пути: middleware, зарегистрированный после маршрута, не запускается, поэтому порядок — граница безопасности; цикл write(), игнорирующий false, даёт OOM под медленными клиентами, поэтому используй pipeline(); запрос без лимита плюс generic JSON.stringify блокирует loop, поэтому пагинируй и используй schema-сериализатор; а фиксированные per-hop таймауты не композируются, поэтому пробрасывай deadline с min(local, remaining). Диагностируй остановку, примени самый рычажный фикс, затем проверь под той же нагрузкой.

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

Trademarks belong to their respective owners. Editorial reference only.