server
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions

This commit is contained in:
Dmitry 2025-12-11 22:24:22 +03:00
parent 4dbdf29926
commit ea1baedb67
2 changed files with 22 additions and 10 deletions

View file

@ -30,7 +30,7 @@ FROM debian:bookworm-slim AS runtime
WORKDIR /app WORKDIR /app
RUN apt-get update \ 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/* && rm -rf /var/lib/apt/lists/*
# App binary # App binary
@ -57,11 +57,13 @@ ENV PORT=3000 \
EXPOSE 3000 EXPOSE 3000
# Healthcheck - проверка доступности сервера # 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 может долго инициализироваться при первом запуске или при большом объеме данных # Isar может долго инициализироваться при первом запуске или при большом объеме данных
# Используем SERVER_ADDRESS, но если он 0.0.0.0, используем 127.0.0.1 для healthcheck (быстрее внутри контейнера) # Используем 127.0.0.1 для healthcheck (внутри контейнера работает даже если сервер слушает на 0.0.0.0)
HEALTHCHECK --interval=10s --timeout=5s --start-period=60s --retries=5 \ # Пробуем curl, если не работает - используем wget как fallback
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' 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 # Start server - все настройки читаются из environment variables
CMD ["/app/server"] CMD ["/app/server"]

View file

@ -41,7 +41,10 @@ class MnemoShelf {
// Чтение переменных окружения вместо CLI аргументов // Чтение переменных окружения вместо CLI аргументов
final addressArg = Platform.environment['SERVER_ADDRESS']; final addressArg = Platform.environment['SERVER_ADDRESS'];
final portArg = Platform.environment['PORT']; 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 port = int.tryParse(portArg ?? '') ?? 3000;
final certs = Platform.environment['CERTS_PATH']; // null = HTTP without SSL final certs = Platform.environment['CERTS_PATH']; // null = HTTP without SSL
final dualMode = Platform.environment['DUAL_MODE'] == 'true' || final dualMode = Platform.environment['DUAL_MODE'] == 'true' ||
@ -148,11 +151,13 @@ class MnemoShelf {
.addHandler(v2Router); .addHandler(v2Router);
final rootRouter = Router() final rootRouter = Router()
..get('/health', (Request request) async { ..get('/health', (Request request) {
// Простой эндпоинт для healthcheck - всегда отвечает OK
// Не используем async для максимальной простоты и скорости
return Response.ok( return Response.ok(
'OK', 'OK',
headers: { headers: {
'Content-Type': 'text/plain', 'Content-Type': 'text/plain; charset=utf-8',
...corsConfig, ...corsConfig,
}, },
); );
@ -195,7 +200,7 @@ class MnemoShelf {
} }
Future<void> _startDualServers( Future<void> _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'); print('🚀 Starting DUAL mode: HTTP + HTTPS servers');
// HTTP сервер на указанном порту // HTTP сервер на указанном порту
@ -265,7 +270,7 @@ class MnemoShelf {
Future<HttpServer> _createServer( Future<HttpServer> _createServer(
Handler handler, Handler handler,
Object address, InternetAddress address,
int port, { int port, {
SecurityContext? securityContext, SecurityContext? securityContext,
int? backlog, int? backlog,
@ -283,7 +288,12 @@ class MnemoShelf {
shared: shared, shared: shared,
requestClientCertificate: true, requestClientCertificate: true,
)); ));
// Запускаем обработку запросов (неблокирующая операция)
// serveRequests запускает обработку запросов в фоне и возвращает управление сразу
shelf_io.serveRequests(server, handler, poweredByHeader: poweredByHeader); 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; return server;
} }
} }