fix(controller): stop migration failures being masked as success
Backfill-миграция V2.3.2 падала на testnet TS-ошибкой компиляции
(mongo.db возможно undefined, strictNullChecks), но deploy-скрипт
(blue-green-deploy.sh) рапортовал успех — 2.3.2 не появилась в
таблице migrations, extensions.capital_program_doc_data_hash осталась
пустой, а Semaphore-лог показывал "Database migrations completed
successfully".
Причина ложноположительного результата — не баг деплой-скрипта, а
Sentry: в production Sentry.init() (enabled: config.env==='production')
ставит process.on('unhandledRejection', ...) с дефолтным mode:'warn',
который перехватывает необработанный reject из bootstrap()'а --migrate
ветки и не роняет процесс — в отличие от штатного поведения голого
Node. В dev (Sentry выключен) тот же баг воспроизводимо валит процесс
exit 1; на testnet — exit 0. Подтверждено локальным воспроизведением
обеих версий на идентичном коде.
Фикс на двух уровнях:
1. index.ts: явный try/catch + process.exit(1) вокруг --migrate и
--migrations-only веток. Не полагаемся на ambient unhandled-rejection
поведение (Sentry/Node/версия) — exit code теперь детерминирован
независимо от окружения.
2. V2.3.2: mongo.db действительно типизирован как возможно undefined —
явная runtime-проверка с throw вместо каста.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -72,6 +72,9 @@ export default {
|
||||
try {
|
||||
mongo = await mongoose.createConnection(config.mongoose.url).asPromise();
|
||||
const db = mongo.db;
|
||||
if (!db) {
|
||||
throw new Error('Подключение к MongoDB установлено, но db не инициализирована');
|
||||
}
|
||||
const collection = db.collection(COLLECTION_NAME);
|
||||
await collection.createIndex({ hash: 1 }, { unique: true });
|
||||
await collection.updateOne(
|
||||
|
||||
@@ -62,15 +62,33 @@ async function bootstrap() {
|
||||
// Проверяем, был ли запущен режим миграций
|
||||
const args = process.argv.slice(2);
|
||||
if (args.includes('--migrate')) {
|
||||
try {
|
||||
await migrateData();
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
// migrateData() уже логирует причину; здесь важен только ненулевой
|
||||
// exit code. В production Sentry.init() ставит свой глобальный
|
||||
// process.on('unhandledRejection', ...) с дефолтным mode: 'warn' —
|
||||
// он перехватывает необработанный reject этого await и НЕ роняет
|
||||
// процесс (в отличие от штатного поведения Node без Sentry). Без
|
||||
// явного process.exit(1) здесь deploy-скрипт получал ложноположительный
|
||||
// exit code 0 при реально упавшей миграции (кейс V2.3.2 на testnet
|
||||
// 2026-07-19 — TS-ошибка компиляции миграции проглатывалась именно так).
|
||||
logger.error('Процесс миграции завершился с ошибкой, выходим с кодом 1', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем, был ли запущен режим только миграций (для обратной совместимости)
|
||||
if (args.includes('--migrations-only')) {
|
||||
try {
|
||||
await migrateData();
|
||||
logger.info('Режим только миграций - миграции выполнены, сервер не будет запущен');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
logger.error('Процесс миграции завершился с ошибкой, выходим с кодом 1', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Подключение к MongoDB
|
||||
|
||||
Reference in New Issue
Block a user