/** * Copyright (c) 2026 Niolla * All rights reserved. */ require("dotenv").config(); const { validateEnvironment } = require("./app/config/env.config"); const bootstrap = async () => { const env = validateEnvironment(); const { initializeDatabase, closeDatabase } = require("./app/config/database.lifecycle"); const { initializeRedis, closeRedis } = require("./app/config/redis.lifecycle"); try { await initializeDatabase(); console.log("Database connection ready."); await initializeRedis(); console.log("Redis connection ready."); } catch (error) { await Promise.allSettled([closeRedis(), closeDatabase()]); throw error; } const { closeQueues } = require("./app/config/queue.lifecycle"); const startAllCrons = require("./cron"); const app = require("./app"); let stopCrons = async () => {}; if (env.RUN_CRON) stopCrons = startAllCrons(); const server = await new Promise((resolve, reject) => { const listener = app.listen(env.PORT, "0.0.0.0", () => resolve(listener)); listener.once("error", reject); }); console.log(`ZUMRI API listening on port ${env.PORT}.`); let shuttingDown = false; const shutdown = async (reason, exitCode = 0) => { if (shuttingDown) return; shuttingDown = true; console.log(`Shutting down (${reason}).`); const forceTimer = setTimeout(() => { console.error("Graceful shutdown timed out."); process.exit(1); }, env.SHUTDOWN_TIMEOUT_MS); forceTimer.unref(); try { await new Promise((resolve) => server.close(resolve)); await stopCrons(); await closeQueues(); await closeRedis(); await closeDatabase(); clearTimeout(forceTimer); process.exit(exitCode); } catch (error) { console.error("Shutdown failed", { name: error.name, message: error.message }); process.exit(1); } }; process.once("SIGTERM", () => shutdown("SIGTERM")); process.once("SIGINT", () => shutdown("SIGINT")); process.once("unhandledRejection", (reason) => { const error = reason instanceof Error ? reason : new Error("Unhandled rejection"); console.error("Unhandled rejection", { name: error.name, message: error.message }); shutdown("unhandledRejection", 1); }); process.once("uncaughtException", (error) => { console.error("Uncaught exception", { name: error.name, message: error.message }); shutdown("uncaughtException", 1); }); return { server, shutdown }; }; if (require.main === module) { bootstrap().catch((error) => { console.error("API startup failed", { name: error.name, message: error.message }); process.exitCode = 1; }); } module.exports = { bootstrap };