-
Notifications
You must be signed in to change notification settings - Fork 16
[Fix] Enhance server.js with graceful shutdown, env validation, and improved error handling #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,16 @@ | ||
| # Copy this file to .env and fill in your values | ||
| MONGO_URI=your_mongodb_connection_string_here | ||
| # Database | ||
| MONGO_URI=mongodb://localhost:27017/your_database_name | ||
|
|
||
| # Server | ||
| PORT=5001 | ||
| NODE_ENV=development | ||
|
|
||
| # Redis | ||
| UPSTASH_REDIS_REST_URL=your_upstash_redis_url_here | ||
| UPSTASH_REDIS_REST_TOKEN=your_upstash_redis_token_here | ||
| JWT_SECRET=any_random_string_for_jwt_secret | ||
|
|
||
| # JWT | ||
| JWT_SECRET=any_random_string_for_jwt_secret | ||
|
|
||
| # CORS - Production ke liye | ||
| ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000 |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,7 @@ import cookieParser from "cookie-parser"; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { fileURLToPath } from "url"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import dns from "dns"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import jwt from "jsonwebtoken"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import mongoose from "mongoose"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Routes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import notesRoutes from "./routes/notesRoutes.js"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -25,24 +26,43 @@ dotenv.config(); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dns.setServers(["1.1.1.1", "8.8.8.8"]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const app = express(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // const PORT = process.env.PORT || 5001; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const __filename = fileURLToPath(import.meta.url); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const __dirname = path.dirname(__filename); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== ENVIRONMENT VALIDATION ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const requiredEnvVars = ["PORT", "MONGO_URI", "JWT_SECRET", "NODE_ENV"]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const validateEnv = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const missing = requiredEnvVars.filter((varName) => !process.env[varName]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (missing.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("Missing required environment variables:"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| missing.forEach((varName) => console.error(` - ${varName}`)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("All required environment variables are present"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validateEnv(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== REDIS CLIENT REFERENCE ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let redisClientInstance = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== MIDDLEWARE ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // CORS Configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (process.env.NODE_ENV !== "production") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.use( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cors({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| origin: "http://localhost:5173", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| credentials: true, // Allow cookies to be sent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| allowedHeaders: ["Content-Type", "Authorization"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const corsOptions = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| origin: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.env.NODE_ENV === "production" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? process.env.ALLOWED_ORIGINS?.split(",") || [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : ["http://localhost:5173", "http://localhost:3000"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| credentials: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| allowedHeaders: ["Content-Type", "Authorization"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| optionsSuccessStatus: 200, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.use(cors(corsOptions)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Body parsing middleware | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.use(express.json()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -70,13 +90,42 @@ app.use("/api", optionalAuthenticateUser); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.use("/api/notes", notesRoutes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.use("/api/auth", authRoutes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== HEALTH CHECK ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.get("/health", (req, res) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res.status(200).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== IMPROVED HEALTH CHECK ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.get("/health", async (req, res) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mongodbStatus = "Disconnected"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let redisStatus = "Disconnected"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mongoose = await import("mongoose"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mongodbStatus = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mongoose.default.connection.readyState === 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "Connected" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "Disconnected"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mongodbStatus = "Error"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (redisClientInstance && redisClientInstance.isReady) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| redisStatus = "Connected"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| redisStatus = "Error"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const healthStatus = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| status: "OK", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Server is running", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timestamp: new Date().toISOString(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uptime: process.uptime(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| services: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mongodb: mongodbStatus, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| redis: redisStatus, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| environment: process.env.NODE_ENV || "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isHealthy = mongodbStatus === "Connected"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res.status(isHealthy ? 200 : 503).json(healthStatus); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+116
to
+128
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Health check Line 117 sets 🐛 Proposed fix+ const isHealthy = mongodbStatus === "Connected";
+
const healthStatus = {
- status: "OK",
+ status: isHealthy ? "OK" : "ERROR",
timestamp: new Date().toISOString(),
uptime: process.uptime(),
services: {
mongodb: mongodbStatus,
redis: redisStatus,
},
environment: process.env.NODE_ENV || "development",
};
- const isHealthy = mongodbStatus === "Connected";
res.status(isHealthy ? 200 : 503).json(healthStatus);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== PRODUCTION STATIC FILES ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -87,36 +136,115 @@ if (process.env.NODE_ENV === "production") { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== ERROR HANDLING ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== IMPROVED ERROR HANDLING ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class AppError extends Error { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| constructor(message, statusCode, details = null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super(message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.statusCode = statusCode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.details = details; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.isOperational = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Error.captureStackTrace(this, this.constructor); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.use((err, req, res, next) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("Error:", err.message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (err instanceof AppError) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(err.statusCode).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| success: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: err.message, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| details: err.details, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(process.env.NODE_ENV === "development" && { stack: err.stack }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res.status(500).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: "Internal server error", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: process.env.NODE_ENV === "development" ? err.message : undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| success: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.env.NODE_ENV === "production" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "Internal server error" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : err.message, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(process.env.NODE_ENV === "development" && { stack: err.stack }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== GRACEFUL SHUTDOWN ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let server = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const gracefulShutdown = async (signal) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`Received ${signal}. Shutting down gracefully...`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const timeout = setTimeout(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("Forced shutdown after timeout"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, 10000); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mongoose = await import("mongoose"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (mongoose.default.connection.readyState === 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await mongoose.default.connection.close(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("MongoDB connection closed"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (redisClientInstance && redisClientInstance.isReady) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await redisClientInstance.quit(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Redis connection closed"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (server) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| server.close(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Server closed successfully"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clearTimeout(timeout); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clearTimeout(timeout); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+183
to
+204
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Map the relevant file first, then read the shutdown-related section with line numbers.
ast-grep outline backend/src/server.js --view expanded || true
wc -l backend/src/server.js
sed -n '1,260p' backend/src/server.js | cat -n
# Find where the HTTP server is created and how requests depend on Mongo/Redis.
rg -n "createServer|listen\\(|server\\.close|gracefulShutdown|redisClientInstance|mongoose|quit\\(|close\\(" backend/src/server.js backend/src -g '!**/node_modules/**'Repository: niharika-mente/ThinkBoard Length of output: 13411 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the route handlers and controllers that run during requests.
ast-grep outline backend/src/routes/notesRoutes.js --view expanded || true
ast-grep outline backend/src/routes/authRoutes.js --view expanded || true
ast-grep outline backend/src/controllers/notesController.js --view expanded || true
ast-grep outline backend/src/controllers/authController.js --view expanded || true
# Read the relevant request-path code with line numbers.
sed -n '1,260p' backend/src/routes/notesRoutes.js | cat -n
sed -n '1,260p' backend/src/routes/authRoutes.js | cat -n
sed -n '1,260p' backend/src/controllers/notesController.js | cat -n
sed -n '1,260p' backend/src/controllers/authController.js | cat -nRepository: niharika-mente/ThinkBoard Length of output: 7722 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect auth and Redis-related middleware used on request paths.
ast-grep outline backend/src/middleware/authMiddleware.js --view expanded || true
ast-grep outline backend/src/middleware/rateLimiter.js --view expanded || true
ast-grep outline backend/src/config/redis.js --view expanded || true
# Read the relevant files with line numbers.
sed -n '1,260p' backend/src/middleware/authMiddleware.js | cat -n
sed -n '1,260p' backend/src/middleware/rateLimiter.js | cat -n
sed -n '1,260p' backend/src/config/redis.js | cat -nRepository: niharika-mente/ThinkBoard Length of output: 3109 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Find all Redis client usages and whether request handlers depend on the server's redisClientInstance.
rg -n "redisClientInstance|connectRedis\\(|ratelimit|Upstash|`@upstash/redis`|redisClient\\." backend/src -g '!**/node_modules/**'
# Inspect the Upstash config referenced by the rate limiter.
ast-grep outline backend/src/config/upstash.js --view expanded || true
sed -n '1,220p' backend/src/config/upstash.js | cat -nRepository: niharika-mente/ThinkBoard Length of output: 1843 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the auth controller used by backend/src/routes/authRoutes.js.
ast-grep outline backend/src/controllers/userAuth.js --view expanded || true
sed -n '1,260p' backend/src/controllers/userAuth.js | cat -nRepository: niharika-mente/ThinkBoard Length of output: 4600 Drain HTTP before closing MongoDB/Redis. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("Error during shutdown:", error.message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clearTimeout(timeout); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ==================== START SERVER ==================== | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const startServer = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Connect to MongoDB | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connectDB(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("MongoDB connected successfully"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Connect to Redis | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await connectRedis(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(" Redis connected successfully"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const redis = await connectRedis(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| redisClientInstance = redis; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Redis connected successfully"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (redisError) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn(" Redis connection failed, continuing without Redis"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn("Redis connection failed, continuing without Redis"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Start Express server | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.listen(process.env.PORT, () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| server = app.listen(process.env.PORT, () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Server listening at port number: " + process.env.PORT); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Environment: " + (process.env.NODE_ENV || "development")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Health check: http://localhost:" + process.env.PORT + "/health", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.on("SIGINT", () => gracefulShutdown("SIGINT")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.on("SIGTERM", () => gracefulShutdown("SIGTERM")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.on("uncaughtException", (error) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("Uncaught Exception:", error); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gracefulShutdown("uncaughtException"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.on("unhandledRejection", (reason, promise) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("Unhandled Rejection:", reason); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gracefulShutdown("unhandledRejection"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error(" Server startup failed:", error.message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("Server startup failed:", error.message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win
Redundant dynamic
import("mongoose")despite static import.mongooseis already statically imported at Line 9, but Lines 99 and 184 re-import it dynamically (await import("mongoose")) and access.default.connection. Since both resolve to the same cached module, this adds unnecessary async overhead on the health-check hot path (frequently polled by load balancers/orchestrators) and in the shutdown path, and creates a confusing shadowedmongoosevariable.♻️ Use the static import directly
app.get("/health", async (req, res) => { let mongodbStatus = "Disconnected"; let redisStatus = "Disconnected"; try { - const mongoose = await import("mongoose"); - mongodbStatus = - mongoose.default.connection.readyState === 1 - ? "Connected" - : "Disconnected"; + mongodbStatus = + mongoose.connection.readyState === 1 ? "Connected" : "Disconnected"; } catch (error) { mongodbStatus = "Error"; }try { - const mongoose = await import("mongoose"); - if (mongoose.default.connection.readyState === 1) { - await mongoose.default.connection.close(); + if (mongoose.connection.readyState === 1) { + await mongoose.connection.close(); console.log("MongoDB connection closed"); }Also applies to: 99-99, 184-184
🤖 Prompt for AI Agents