diff --git a/backend/Dockerfile b/backend/Dockerfile index e9cbc65..5c4a5f7 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -21,6 +21,10 @@ EXPOSE 3000 ENV NODE_ENV=production ENV NODE_NO_WARNINGS=1 +# Healthcheck для Docker +HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ + CMD node -e "require('http').get('http://localhost:3000/health/live', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" + # Явно выводим логи в stdout/stderr без буферизации # Используем unbuffered mode для Python-style вывода (если доступно) CMD sh -c "echo '========================================' 1>&2 && echo '=== DOCKER CMD STARTED ===' 1>&2 && echo '========================================' 1>&2 && echo 'Running migrations...' 1>&2 && npx prisma migrate deploy 2>&1 && echo '=== MIGRATIONS COMPLETED ===' 1>&2 && echo 'Starting Node.js application...' 1>&2 && exec node --no-warnings dist/main 2>&1" diff --git a/backend/src/app.controller.ts b/backend/src/app.controller.ts index cce879e..bf55e1e 100644 --- a/backend/src/app.controller.ts +++ b/backend/src/app.controller.ts @@ -1,12 +1,69 @@ import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; +import { PrismaService } from './prisma/prisma.service'; @Controller() export class AppController { - constructor(private readonly appService: AppService) {} + constructor( + private readonly appService: AppService, + private readonly prisma: PrismaService, + ) {} @Get() getHello(): string { return this.appService.getHello(); } + + @Get('health') + async health() { + const health = { + status: 'ok', + timestamp: new Date().toISOString(), + uptime: process.uptime(), + environment: process.env.NODE_ENV || 'development', + }; + + // Проверяем подключение к БД + try { + await this.prisma.$queryRaw`SELECT 1`; + return { + ...health, + database: 'connected', + }; + } catch (error) { + return { + ...health, + database: 'disconnected', + error: error.message, + }; + } + } + + @Get('health/live') + liveness() { + return { + status: 'alive', + timestamp: new Date().toISOString(), + }; + } + + @Get('health/ready') + async readiness() { + try { + // Проверяем подключение к БД + await this.prisma.$queryRaw`SELECT 1`; + return { + status: 'ready', + timestamp: new Date().toISOString(), + database: 'connected', + }; + } catch (error) { + return { + status: 'not ready', + timestamp: new Date().toISOString(), + database: 'disconnected', + error: error.message, + }; + } + } }