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:
+55
-26
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user