import http from "http"; import { DateTime } from "luxon"; import { createApp } from "./app"; import { ENV } from "./config"; import { connectToDatabase } from "./config/database"; import { logger } from "./core/common/infrastructure/logger"; // Guardamos información del estado del servidor export const currentState = { launchedAt: DateTime.now(), appPath: process.cwd(), host: ENV.HOST, port: ENV.PORT, environment: ENV.NODE_ENV, connections: {} as Record, }; // Manejo de cierre forzado del servidor (graceful shutdown) const serverStop = (server: http.Server) => { const forceTimeout = 30000; return new Promise((resolve, reject) => { logger.warn("⚡️ Shutting down server"); setTimeout(() => { logger.error("Could not close connections in time, forcefully shutting down"); resolve(); }, forceTimeout).unref(); server.close((err) => { if (err) { return reject(err); } logger.info("Closed out remaining connections."); logger.info("❎ Bye!"); resolve(); }); }); }; // Manejo de errores al iniciar el servidor const serverError = (error: NodeJS.ErrnoException) => { logger.info(`⛔️ Server wasn't able to start properly.`); if (error.code === "EADDRINUSE") { logger.error(error.message); //logger.error(`The port ${error.port} is already used by another application.`); } else { logger.error(error); } // Dependiendo de la criticidad, podrías forzar el proceso a salir process.exit(1); }; // Almacena en "connections" cada nueva conexión (descomentar si se quiere seguimiento) const serverConnection = (conn: any) => { const key = `${conn.remoteAddress}:${conn.remotePort}`; currentState.connections[key] = conn; conn.on("close", () => { delete currentState.connections[key]; }); }; //const sequelizeConn = createSequelizeAdapter(); //const firebirdConn = createFirebirdAdapter(); // Crea el servidor HTTP const server = http .createServer(createApp()) .once("listening", () => process.on("SIGINT", async () => { // Por ejemplo, podrías desconectar la base de datos aquí: // firebirdConn.disconnect(); // O forzar desconexión en adapters // sequelizeConn.close(); await serverStop(server); }) ) .on("close", () => logger.info(`Shut down at: ${DateTime.now().toLocaleString(DateTime.DATETIME_FULL)}`) ) .on("connection", serverConnection) .on("error", serverError); // Ejemplo de adapters de base de datos (descoméntalos si los necesitas) // const sequelizeConn = createSequelizeAdapter(); // const firebirdConn = createFirebirdAdapter(); // Manejo de promesas no capturadas process.on("unhandledRejection", (reason: any, promise: Promise) => { logger.error("❌ Unhandled rejection at:", promise, "reason:", reason); // Dependiendo de la aplicación, podrías desear una salida total o un cierre controlado process.exit(1); }); // Manejo de excepciones no controladas process.on("uncaughtException", (error: Error) => { // firebirdConn.disconnect(); logger.error(`❌ Uncaught exception:`, error.message); logger.error(error.stack); // process.exit(1); }); // Arranca el servidor si la conexión a la base de datos va bien (async () => { try { const now = DateTime.now(); logger.info(`Time: ${now.toLocaleString(DateTime.DATETIME_FULL)} ${now.zoneName}`); logger.info(`Launched in: ${now.diff(currentState.launchedAt).toMillis()} ms`); logger.info(`Environment: ${currentState.environment}`); logger.info(`Process PID: ${process.pid}`); await connectToDatabase(); // Lógica de inicialización de DB, si procede: // initStructure(sequelizeConn.connection); // insertUsers(); server.listen(currentState.port, () => { logger.info("To shut down your server, press + C at any time"); logger.info(`⚡️ Server: http://${currentState.host}:${currentState.port}`); }); } catch (error) { serverError(error as NodeJS.ErrnoException); } })();