fix(reliability): multer-ошибки, process-хендлеры, анти-гонка питомца, flashcards (Спринт2)

- errorHandler: MulterError → 413 «слишком большой» / 400 (а не 500).
- server: process.on(unhandledRejection/uncaughtException) — глобальная страховка
  с логированием, процесс не падает от единичной асинхронной ошибки.
- pet: атомарный CAS на кулдаунах petAction/starCatch/feedPet
  (UPDATE ... WHERE last IS ?, начисление только при changes=1) — нет двойного
  начисления при параллельных запросах. Проверено на семантике node:sqlite.
- assistant.flashcardsFromText: await callLLMFailover в try/catch → 502 вместо
  необработанного отклонения промиса.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-12 22:08:02 +03:00
parent 646e93cf46
commit 09c6c2b21d
4 changed files with 34 additions and 6 deletions
+9
View File
@@ -549,3 +549,12 @@ function shutdown(signal) {
}
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
/* ── Глобальная страховка: не валим процесс на единичной асинхронной ошибке.
Логируем (с requestId недоступен здесь — это вне цикла запроса) и продолжаем. */
process.on('unhandledRejection', (reason) => {
logger.error('unhandledRejection', { err: (reason && reason.message) || String(reason), stack: reason && reason.stack });
});
process.on('uncaughtException', (err) => {
logger.error('uncaughtException', { err: err && err.message, stack: err && err.stack });
});