diff --git a/mnemo_cards_backend/Dockerfile b/mnemo_cards_backend/Dockerfile index 30df63c..8798d8d 100644 --- a/mnemo_cards_backend/Dockerfile +++ b/mnemo_cards_backend/Dockerfile @@ -30,7 +30,7 @@ FROM debian:bookworm-slim AS runtime WORKDIR /app RUN apt-get update \ - && apt-get install -y --no-install-recommends ca-certificates openssl curl \ + && apt-get install -y --no-install-recommends ca-certificates openssl curl wget \ && rm -rf /var/lib/apt/lists/* # App binary @@ -57,11 +57,13 @@ ENV PORT=3000 \ EXPOSE 3000 # Healthcheck - проверка доступности сервера -# Increased start-period to 60s to allow server initialization (Isar DB, cron jobs, etc.) +# Increased start-period to 90s to allow server initialization (Isar DB, cron jobs, etc.) # Isar может долго инициализироваться при первом запуске или при большом объеме данных -# Используем SERVER_ADDRESS, но если он 0.0.0.0, используем 127.0.0.1 для healthcheck (быстрее внутри контейнера) -HEALTHCHECK --interval=10s --timeout=5s --start-period=60s --retries=5 \ - CMD sh -c 'address=${SERVER_ADDRESS:-0.0.0.0}; [ "$address" = "0.0.0.0" ] && address=127.0.0.1; curl -f --max-time 5 --connect-timeout 2 http://${address}:${PORT:-3000}/health || exit 1' +# Используем 127.0.0.1 для healthcheck (внутри контейнера работает даже если сервер слушает на 0.0.0.0) +# Пробуем curl, если не работает - используем wget как fallback +HEALTHCHECK --interval=10s --timeout=10s --start-period=90s --retries=3 \ + CMD curl -f -sS --max-time 8 --connect-timeout 3 http://127.0.0.1:${PORT:-3000}/health > /dev/null 2>&1 || \ + wget --quiet --tries=1 --timeout=8 --spider http://127.0.0.1:${PORT:-3000}/health || exit 1 # Start server - все настройки читаются из environment variables CMD ["/app/server"] diff --git a/mnemo_cards_backend/lib/api/mnemo_shelf.dart b/mnemo_cards_backend/lib/api/mnemo_shelf.dart index 1224aa4..6229973 100644 --- a/mnemo_cards_backend/lib/api/mnemo_shelf.dart +++ b/mnemo_cards_backend/lib/api/mnemo_shelf.dart @@ -41,7 +41,10 @@ class MnemoShelf { // Чтение переменных окружения вместо CLI аргументов final addressArg = Platform.environment['SERVER_ADDRESS']; final portArg = Platform.environment['PORT']; - final address = addressArg ?? InternetAddress.anyIPv4.address; + // Используем InternetAddress напрямую для правильной работы с bind + final address = addressArg != null && addressArg != '0.0.0.0' + ? InternetAddress(addressArg) + : InternetAddress.anyIPv4; final port = int.tryParse(portArg ?? '') ?? 3000; final certs = Platform.environment['CERTS_PATH']; // null = HTTP without SSL final dualMode = Platform.environment['DUAL_MODE'] == 'true' || @@ -148,11 +151,13 @@ class MnemoShelf { .addHandler(v2Router); final rootRouter = Router() - ..get('/health', (Request request) async { + ..get('/health', (Request request) { + // Простой эндпоинт для healthcheck - всегда отвечает OK + // Не используем async для максимальной простоты и скорости return Response.ok( 'OK', headers: { - 'Content-Type': 'text/plain', + 'Content-Type': 'text/plain; charset=utf-8', ...corsConfig, }, ); @@ -195,7 +200,7 @@ class MnemoShelf { } Future _startDualServers( - Handler handler, Object address, int port, String? certs) async { + Handler handler, InternetAddress address, int port, String? certs) async { print('🚀 Starting DUAL mode: HTTP + HTTPS servers'); // HTTP сервер на указанном порту @@ -265,7 +270,7 @@ class MnemoShelf { Future _createServer( Handler handler, - Object address, + InternetAddress address, int port, { SecurityContext? securityContext, int? backlog, @@ -283,7 +288,12 @@ class MnemoShelf { shared: shared, requestClientCertificate: true, )); + // Запускаем обработку запросов (неблокирующая операция) + // serveRequests запускает обработку запросов в фоне и возвращает управление сразу shelf_io.serveRequests(server, handler, poweredByHeader: poweredByHeader); + // Даем серверу небольшое время на инициализацию обработчика запросов + await Future.delayed(const Duration(milliseconds: 100)); + print('✅ Server bound and ready to accept connections on ${server.address.address}:${server.port}'); return server; } }