Just wanted to share a quick note on how we're making our Node.js applications more robust by implementing comprehensive error handling. It's crucial for maintaining a stable and reliable server.
Here's a look at some of the common types of server errors we explicitly handle, along with the code we use:
1. Unhandled Rejection Errors (Promises)
These occur when a Promise is rejected but there's no .catch()
handler to deal with the error. If left unhandled, it can crash your application. We listen for the unhandledRejection
event to gracefully shut down the server, ensuring no lingering processes.
process.on("unhandledRejection", (err) => {
console.log('Unhandled Rejection detected! Server shutting down..', err);
// Close the server if it's running
if (server) {
server.close(() => {
process.exit(1); // Exit with a failure code
});
}
process.exit(1); // Exit immediately if server isn't active
});
// Example of an unhandled rejection (you'd typically remove this in production)
// Promise.reject(new Error("I forgot to catch this promise"));
2. Uncaught Exception Errors (Synchronous Code)
These are synchronous errors that are not caught by a try...catch
block. Think of things like referencing an undefined variable or a typo that leads to a runtime error. The uncaughtException
event helps us catch these, log them, and perform a controlled shutdown.
process.on("uncaughtException", (err) => {
console.log('Uncaught Exception detected! Server shutting down..', err);
// Close the server if it's running
if (server) {
server.close(() => {
process.exit(1); // Exit with a failure code
});
}
process.exit(1); // Exit immediately if server isn't active
});
// Example of an uncaught exception (you'd typically remove this in production)
// throw new Error("I forgot to handle this local error.");
3. Signal Termination Errors (SIGTERM
and SIGINT
)
These aren't errors in the traditional sense, but rather signals from the operating system to terminate a process. By listening for these signals, we can ensure our server closes properly, freeing up resources and preventing unexpected behavior.
-
SIGTERM
: This is a generic termination signal, often sent by process managers (like PM2 or Kubernetes) to gracefully shut down an application. It gives the application a chance to clean up resources before exiting.
process.on("SIGTERM", (err) => { console.log('Sigterm signal received! Server shutting down..', err); // Close the server if it's running if (server) { server.close(() => { process.exit(1); // Exit with a failure code }); } process.exit(1); // Exit immediately if server isn't active });
-
SIGINT
: This signal is typically sent when you pressCtrl+C
in your terminal to interrupt a running process.
process.on("SIGINT", (err) => { console.log('Sigint signal received! Server shutting down..', err); // Close the server if it's running if (server) { server.close(() => { process.exit(1); // Exit with a failure code }); } process.exit(1); // Exit immediately if server isn't active });
Implementing these error handling mechanisms helps us build more resilient applications that can withstand unexpected issues and shut down cleanly when needed.
What are your go-to strategies for handling errors in your Node.js applications? Share in the comments! 👇
Top comments (0)