feat: stabilize API startup and lifecycle management

- Refactor server initialization to separate concerns and improve error handling.
- Implement centralized environment validation using Zod.
- Introduce database, Redis, and queue lifecycle management.
- Add health check endpoints for liveness and readiness.
- Enhance error handling middleware for better response structure.
- Implement rate limiting for API endpoints.
- Add request ID middleware for traceability.
- Create Sequelize CLI configuration and baseline migration for schema management.
- Establish CI workflow with Gitea for testing and syntax checks.
- Document foundational changes and migration strategy in PHASE_0_FOUNDATION_STABILIZATION.md.
- Add Docker Compose configuration for local development and testing.
- Implement unit and integration tests for critical functionality.
This commit is contained in:
Sathira Sri Sathara
2026-09-03 13:33:26 +05:30
parent 624fce31c5
commit 267e80e2ec
40 changed files with 1682 additions and 261 deletions
+55 -26
View File
@@ -1,34 +1,63 @@
/**
* Copyright (c) 2026 Niolla
* All rights reserved.
*
* This source code is proprietary and confidential.
* Unauthorized copying, modification, distribution, or use
* of this file, via any medium, is strictly prohibited.
*/
// app/workers/index.js
require("dotenv").config();
const { validateEnvironment } = require("../config/env.config");
require("dotenv").config()
const createActivityWorker = require("./activity.worker");
const createLogWorker = require("./log.worker");
const createDocumentWorker = require("./document.worker");
// Import future workers here
// const createEmailWorker = require("./email.worker");
console.log("🚀 Starting workers...");
// Initialize workers (async now)
(async () => {
const startWorkers = async () => {
const env = validateEnvironment();
const { initializeDatabase, closeDatabase } = require("../config/database.lifecycle");
const { initializeRedis, closeRedis } = require("../config/redis.lifecycle");
try {
createActivityWorker();
createLogWorker();
await createDocumentWorker();
console.log("✅ All workers started");
} catch (err) {
console.error("❌ Error starting workers:", err.message);
process.exit(1);
await initializeDatabase();
await initializeRedis();
} catch (error) {
await Promise.allSettled([closeRedis(), closeDatabase()]);
throw error;
}
})();
const { closeQueues } = require("../config/queue.lifecycle");
const createActivityWorker = require("./activity.worker");
const createLogWorker = require("./log.worker");
const createDocumentWorker = require("./document.worker");
const workers = [createActivityWorker(), createLogWorker(), await createDocumentWorker()];
console.log("All workers started.");
let shuttingDown = false;
const shutdown = async (reason, exitCode = 0) => {
if (shuttingDown) return;
shuttingDown = true;
console.log(`Workers shutting down (${reason}).`);
const forceTimer = setTimeout(() => process.exit(1), env.SHUTDOWN_TIMEOUT_MS);
forceTimer.unref();
await Promise.allSettled(workers.map((worker) => worker.close()));
await closeQueues();
await closeRedis();
await closeDatabase();
clearTimeout(forceTimer);
process.exit(exitCode);
};
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 worker rejection", { name: error.name, message: error.message });
shutdown("unhandledRejection", 1);
});
process.once("uncaughtException", (error) => {
console.error("Uncaught worker exception", { name: error.name, message: error.message });
shutdown("uncaughtException", 1);
});
};
if (require.main === module) {
startWorkers().catch((error) => {
console.error("Worker startup failed", { name: error.name, message: error.message });
process.exitCode = 1;
});
}
module.exports = { startWorkers };