import "dotenv/config"; import "reflect-metadata"; import cors from "cors"; import express from "express"; import swaggerUi from "swagger-ui-express"; import swaggerDocument from "./swagger.json"; import * as cron from "node-cron"; import { init as rabbitmqInit } from "./services/rabbitmq"; import error from "./middlewares/error"; import { AppDataSource } from "./database/data-source"; import { RegisterRoutes } from "./routes"; import { OrganizationController } from "./controllers/OrganizationController"; import logMiddleware from "./middlewares/logs"; import { logMemoryStore } from "./utils/LogMemoryStore"; import { orgStructureCache } from "./utils/OrgStructureCache"; import { CommandController } from "./controllers/CommandController"; import { ProfileSalaryController } from "./controllers/ProfileSalaryController"; import { DateSerializer } from "./interfaces/date-serializer"; import { initWebSocket } from "./services/webSocket"; async function main() { await AppDataSource.initialize(); // Initialize LogMemoryStore after database is ready logMemoryStore.initialize(); // Initialize OrgStructureCache after database is ready orgStructureCache.initialize(); // Setup custom Date serialization for local timezone DateSerializer.setupDateSerialization(); initWebSocket(); const app = express(); app.use( cors({ origin: "*", }), ); app.use(express.json({ limit: "50mb" })); app.use(express.urlencoded({ extended: true, limit: "50mb" })); app.use(logMiddleware); app.use("/", express.static("static")); app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument)); RegisterRoutes(app); app.use(error); const APP_HOST = process.env.APP_HOST || "0.0.0.0"; const APP_PORT = +(process.env.APP_PORT || 3000); const cronTime = "0 0 3 * * *"; // ตั้งเวลาทุกวันเวลา 03:00:00 // const cronTime = "*/10 * * * * *"; cron.schedule(cronTime, async () => { try { const orgController = new OrganizationController(); await orgController.cronjobRevision(); } catch (error) { console.error("Error executing function from controller:", error); } }); const cronTime_command = "0 0 2 * * *"; // const cronTime_command = "*/10 * * * * *"; cron.schedule(cronTime_command, async () => { try { const commandController = new CommandController(); await commandController.cronjobCommand(); } catch (error) { console.error("Error executing function from controller:", error); } }); const cronTime_Oct = "0 0 1 10 *"; cron.schedule(cronTime_Oct, async () => { try { const commandController = new CommandController(); await commandController.cronjobUpdateRetirementStatus(); } catch (error) { console.error("Error executing function from controller:", error); } }); const cronTime_Tenure = "0 0 0 * * *"; cron.schedule(cronTime_Tenure, async () => { try { const profileSalaryController = new ProfileSalaryController(); await profileSalaryController.cronjobTenurePositionOfficer(); await profileSalaryController.cronjobTenureLevelOfficer(); await profileSalaryController.cronjobTenureExecutivePositionOfficer(); await profileSalaryController.cronjobTenurePositionEmployee(); await profileSalaryController.cronjobTenureLevelEmployee(); await profileSalaryController.Registry(); await profileSalaryController.RegistryEmployee(); } catch (error) { console.error("Error executing function from controller:", error); } }); // app.listen(APP_PORT, APP_HOST, () => console.log(`Listening on: http://localhost:${APP_PORT}`)); const server = app.listen( APP_PORT, APP_HOST, () => ( console.log(`[APP] Application is running on: http://localhost:${APP_PORT}`), console.log(`[APP] Swagger on: http://localhost:${APP_PORT}/api-docs`) ), ); async function runMessageQueue() { try { await rabbitmqInit(); } catch (e) { console.log(e); setTimeout(runMessageQueue, 1000); } } runMessageQueue(); // Graceful Shutdown const gracefulShutdown = async (signal: string) => { console.log(`\n[APP] ${signal} received. Starting graceful shutdown...`); // Stop accepting new connections server.close(() => { console.log("[APP] HTTP server closed"); }); // Force close after timeout const shutdownTimeout = setTimeout(() => { console.error("[APP] Forced shutdown after timeout"); process.exit(1); }, 30000); // 30 seconds timeout try { // Close database connections if (AppDataSource.isInitialized) { await AppDataSource.destroy(); console.log("[APP] Database connections closed"); } // Destroy LogMemoryStore logMemoryStore.destroy(); console.log("[APP] LogMemoryStore destroyed"); // Destroy OrgStructureCache orgStructureCache.destroy(); console.log("[APP] OrgStructureCache destroyed"); clearTimeout(shutdownTimeout); console.log("[APP] Graceful shutdown completed"); process.exit(0); } catch (error) { console.error("[APP] Error during shutdown:", error); clearTimeout(shutdownTimeout); process.exit(1); } }; // Listen for shutdown signals process.on("SIGTERM", () => gracefulShutdown("SIGTERM")); process.on("SIGINT", () => gracefulShutdown("SIGINT")); } main();