Node.js и AWS для high-load инвентаризации: event-driven подход без головной боли

#nodejs#aws#event-driven#inventory

Последний раз, когда я разбирал скачок latency в 400% на одном из warehouse-проектов, виновником оказался синхронный инвентаризационный апдейт. Проблема классическая — пока один сервис честно блокировал строки в SQL, другие уже успевали отправить клиенту устаревшие данные о наличии товара.

Почему event-driven — не модное слово, а necessity

Нагрузка в 10K+ inventory-ивентов в час — это не про «давайте поставим Redis и забудем». Три главных pain point в таких системах:

  1. Duplicate events: два сканера штрихкодов отправили одинаковый ивент
  2. Visibility lag: пока данные идут через цепочку сервисов, кладовщик видит устаревший баланс
  3. Cascading failures: падение одного сервиса не должно блокировать прием новых поставок
// Типичный антипаттерн (но 80% кода в дикой природе)
app.post('/inventory', async (req, res) => {
  await db.transaction(async (tx) => {
    await tx.update('warehouse_balance', ...);
    await tx.insert('audit_log', ...);
    await externalERP.sync();
  }); // 3+ секунд блокировки
});

Event sourcing на минималках

Вместо синхронного апдейта всех систем:

  1. Принимаем ивент и сразу кладем в SQS/SNS
  2. Отдельный воркер обрабатывает с идемпотентностью:
const handler = async (event) => {
  if (await dynamodb.get({id: event.dedupeId})) {
    return; // уже обработано
  }
  
  await Promise.all([
    updateStock(event),
    notifyWarehouseUI(event),
    syncSlowERP(event) // даже если упадет - повторим позже
  ]);
  
  await dynamodb.put({id: event.dedupeId});
};
  1. S3 как source of truth — все ивенты пишем в партиционированный JSON (год/месяц/день/час)

Чего не хватает в Node.js из коробки

  1. Нет нормального batch processing — приходится самому собирать пачки через p-queue или аналоги
  2. Слабовато с backpressure — если RabbitMQ/SQS завалит воркеры сообщениями, процесс умрет без proper circuit breaker
  3. Мониторинг — без метрик в CloudWatch вы даже не поймете, в какой момент началась деградация

На практике приходится допиливать:

Когда асинхронность больно бьет по UX

Главный trade-off такого подхода — eventual consistency. Пока все воркеры отработают:

Наш workaround — hybrid подход:

  1. Cache-aside для UI: при любом ивенте сразу инвалидируем кеш
  2. Synthetic events: если ERP не ответил за 5 секунд — создаем фоновый retry
  3. Priority lanes: события от сканеров обрабатываем в отдельной high-priority очереди

Если ваш CTO говорит «нужно 100% consistency» — покажите ему CAP-теорему и счет за Aurora Global Database. В реальном мире 500ms lag — приемлемая плата за отказоустойчивость.

P.S. Для особо параноидальных — пробуйте Rust+Tokio вместо Node.js, но готовьтесь к 3x разработки.


Источник: https://dev.to/mahir_amaan_0f5bfc60bb9b7/how-to-build-an-inventory-management-solution-for-high-volume-warehouses-using-nodejs-and-aws-3i8h