diff --git a/back/config/index.ts b/back/config/index.ts index f7c7a54c..fb1c9ca5 100644 --- a/back/config/index.ts +++ b/back/config/index.ts @@ -9,6 +9,8 @@ dotenv.config({ interface Config { port: number; grpcPort: number; + bindHost: string; + bindHostGrpc: string; nodeEnv: string; isDevelopment: boolean; isProduction: boolean; @@ -31,6 +33,8 @@ interface Config { const config: Config = { port: parseInt(process.env.BACK_PORT || '5700', 10), grpcPort: parseInt(process.env.GRPC_PORT || '5500', 10), + bindHost: process.env.BIND_HOST || '::', + bindHostGrpc: process.env.BIND_HOST_GRPC || '::', nodeEnv: process.env.NODE_ENV || 'development', isDevelopment: process.env.NODE_ENV === 'development', isProduction: process.env.NODE_ENV === 'production', diff --git a/back/schedule/client.ts b/back/schedule/client.ts index 99bf364a..6b086452 100644 --- a/back/schedule/client.ts +++ b/back/schedule/client.ts @@ -10,7 +10,7 @@ import config from '../config'; class Client { private client = new CronClient( - `0.0.0.0:${config.grpcPort}`, + `localhost:${config.grpcPort}`, credentials.createInsecure(), { 'grpc.enable_http_proxy': 0 }, ); diff --git a/back/services/grpc.ts b/back/services/grpc.ts index e8ea2282..5edd9d2c 100644 --- a/back/services/grpc.ts +++ b/back/services/grpc.ts @@ -16,6 +16,13 @@ import { Service } from 'typedi'; export class GrpcServerService { private server: Server = new Server({ 'grpc.enable_http_proxy': 0 }); + private formatGrpcAddress(host: string, port: number): string { + if (host === '::') { + return `[::]:${port}`; + } + return `${host}:${port}`; + } + async initialize() { try { this.server.addService(HealthService, { check }); @@ -23,18 +30,32 @@ export class GrpcServerService { this.server.addService(ApiService, Api); const grpcPort = config.grpcPort; + const hostsToTry = [ + config.bindHostGrpc, + ...(config.bindHostGrpc !== '0.0.0.0' ? ['0.0.0.0'] : []) + ]; const bindAsync = promisify(this.server.bindAsync).bind(this.server); - await bindAsync( - `0.0.0.0:${grpcPort}`, - ServerCredentials.createInsecure(), - ); - Logger.debug(`✌️ gRPC service started successfully`); - metricsService.record('grpc_service_start', 1, { - port: grpcPort.toString(), - }); + let lastError: Error | null = null; - return grpcPort; + for (const host of hostsToTry) { + try { + const address = this.formatGrpcAddress(host, grpcPort); + await bindAsync(address, ServerCredentials.createInsecure()); + Logger.debug(`✌️ gRPC service started successfully on ${address}`); + metricsService.record('grpc_service_start', 1, { + port: grpcPort.toString(), + host + }); + return grpcPort; + } catch (err) { + lastError = err as Error; + Logger.warn(`Failed to bind gRPC on ${host}:${grpcPort}, trying next...`, err); + } + } + + Logger.error('Failed to start gRPC service on all hosts'); + throw lastError || new Error('Failed to start gRPC service'); } catch (err) { Logger.error('Failed to start gRPC service:', err); throw err; diff --git a/back/services/http.ts b/back/services/http.ts index 5391c842..bbce8ff7 100644 --- a/back/services/http.ts +++ b/back/services/http.ts @@ -3,31 +3,51 @@ import Logger from '../loaders/logger'; import { metricsService } from './metrics'; import { Service } from 'typedi'; import { Server } from 'http'; +import config from '../config'; @Service() export class HttpServerService { private server?: Server = undefined; async initialize(expressApp: express.Application, port: number) { - try { - return new Promise((resolve, reject) => { - this.server = expressApp.listen(port, '0.0.0.0', () => { - Logger.debug(`✌️ HTTP service started successfully`); - metricsService.record('http_service_start', 1, { - port: port.toString(), - }); - resolve(this.server); - }); + const hostsToTry = [ + config.bindHost, + ...(config.bindHost !== '0.0.0.0' ? ['0.0.0.0'] : []) + ]; - this.server?.on('error', (err: Error) => { - Logger.error('Failed to start HTTP service:', err); - reject(err); + let lastError: Error | null = null; + + for (const host of hostsToTry) { + try { + const server = await this.tryListen(expressApp, port, host); + Logger.debug(`✌️ HTTP service started successfully on ${host}:${port}`); + metricsService.record('http_service_start', 1, { + port: port.toString(), + host }); - }); - } catch (err) { - Logger.error('Failed to start HTTP service:', err); - throw err; + this.server = server; + return server; + } catch (err) { + lastError = err as Error; + Logger.warn(`Failed to bind HTTP on ${host}:${port}, trying next...`, err); + } } + + Logger.error('Failed to start HTTP service on all hosts'); + throw lastError || new Error('Failed to start HTTP service'); + } + + private async tryListen(expressApp: express.Application, port: number, host: string): Promise { + return new Promise((resolve, reject) => { + const server = expressApp.listen(port, host, () => { + resolve(server); + }); + + server.on('error', (err: Error) => { + server.close(); + reject(err); + }); + }); } async shutdown() {