NestJSSeniorExperience
Какие production-риски есть у NestJS: blocking code, connection pooling, config, auth, observability, deploy или graceful shutdown?
Ключевые production-риски NestJS: блокирующий код в event loop, утечки соединений с БД, неверная конфигурация секретов, отсутствие graceful shutdown и слепые зоны в observability (нет tracing).
Production-риски NestJS-приложений
Blocking code и Event Loop
Node.js однопоточен. Синхронные CPU-тяжёлые операции (парсинг больших JSON, криптография без async, bcrypt с высоким cost factor) блокируют event loop и снижают throughput для всех запросов.
// Плохо: блокирует event loop
@Post('hash')
hashPassword(@Body('password') pwd: string) {
return bcrypt.hashSync(pwd, 12); // синхронный вызов!
}
// Хорошо: async версия
@Post('hash')
async hashPassword(@Body('password') pwd: string) {
return bcrypt.hash(pwd, 12); // возвращает Promise
}
Connection Pooling
TypeORM по умолчанию создаёт пул из 10 соединений. При высокой нагрузке или медленных запросах пул исчерпывается.
TypeOrmModule.forRoot({
type: 'postgres',
extra: {
max: 20, // размер пула
idleTimeoutMillis: 30000, // закрывать простаивающие
connectionTimeoutMillis: 5000,
},
keepConnectionAlive: false, // не держать соединение при тестах
})
Конфигурация и секреты
- Валидируйте все переменные окружения при старте через Joi или class-validator.
- Никогда не логируйте
process.envцеликом — туда попадают JWT_SECRET, DB_PASSWORD. - В Kubernetes используйте Secrets, не ConfigMaps для чувствительных данных.
Auth-риски
// Частая ошибка: глобальный guard не покрывает новые маршруты
// Правильно: default-deny через глобальный JwtAuthGuard + @Public() для исключений
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
const isPublic = this.reflector.getAllAndOverride<boolean>(
IS_PUBLIC_KEY,
[context.getHandler(), context.getClass()],
);
if (isPublic) return true;
return super.canActivate(context);
}
}
Observability
// Логирование: структурированный JSON для Loki/ELK
import { Logger } from '@nestjs/common';
// Или pino через nestjs-pino
import { LoggerModule } from 'nestjs-pino';
LoggerModule.forRoot({
pinoHttp: {
transport: process.env.NODE_ENV !== 'production'
? { target: 'pino-pretty' }
: undefined,
redact: ['req.headers.authorization'], // скрывать токены
},
})
Graceful Shutdown
// main.ts
const app = await NestFactory.create(AppModule);
app.enableShutdownHooks(); // включает OnApplicationShutdown
// service.ts
@Injectable()
export class DatabaseService implements OnApplicationShutdown {
async onApplicationShutdown(signal: string) {
await this.dataSource.destroy(); // закрыть пул соединений
console.log(`Shutting down on signal: ${signal}`);
}
}
// main.ts — перехват SIGTERM
process.on('SIGTERM', () => app.close());
Deploy-риски
- Health check должен проверять зависимости (БД, Redis) через
@nestjs/terminus. - Rolling deploy без graceful shutdown дропает in-flight запросы.
Подводные камни
- Interceptors с
tap()из RxJS не перехватывают исключения — используйтеcatchError()для обработки ошибок внутри interceptor. - Memory leaks через незакрытые EventEmitter подписки в
onModuleInitбез соответствующегоonModuleDestroy. - Отсутствие rate limiting на публичных эндпоинтах — добавьте
@nestjs/throttlerдаже на MVP. - Некорректный порядок middleware: CORS должен стоять до AuthGuard, иначе preflight OPTIONS-запросы возвращают 401.
- Без
helmet()приложение уязвимо к XSS и clickjacking — добавьте как глобальный middleware. - Запуск без кластеризации (cluster module или PM2) означает, что один Node.js процесс использует одно ядро; на 8-ядерном сервере 7 ядер простаивают.
- Необработанные Promise rejections без глобального фильтра могут упасть тихо или крашнуть процесс в зависимости от версии Node.
What hurts your answer
- Говорить только о запуске NestJS, но не об эксплуатации
- Не упоминать observability, обновления, безопасность и rollback
- Описывать риски абстрактно, без способов их снижать
What they're listening for
- Видит production-риски NestJS
- Говорит про monitoring, rollout, rollback и безопасность
- Умеет ранжировать риски по вероятности и влиянию