Graceful Shutdowns in Node.js: How to Handle Cleanup Before Exit
There are a few ways to achieve cleanup actions:
function cleanupHandler() {
console.log('Cleaning up resources...');
// Your cleanup logic here (e.g., closing files, database connections)
}
process.on('exit', cleanupHandler);
// Your main program logic here
// Simulate an error (uncomment to trigger abnormal exit)
// throw new Error('Something went wrong!');
In this example, the cleanupHandler
function is registered to run when the process exits. You can replace the console.log
with your actual cleanup logic, like closing files or database connections.
Using node-cleanup package:
const cleanup = require('node-cleanup');
function cleanupHandler() {
console.log('Cleaning up with node-cleanup...');
// Your cleanup logic here
}
cleanup(cleanupHandler);
// Your main program logic here
// Simulate an error (uncomment to trigger abnormal exit)
// throw new Error('Something went wrong!');
Here, we use the node-cleanup
package. The cleanup
function registers the cleanupHandler
to be called on exit. This approach offers a more modular way to handle cleanup.
Remember:
- Replace the
console.log
statements with your specific cleanup tasks. - These examples are basic. You might need to handle asynchronous cleanup operations (e.g., waiting for a database connection to close) appropriately.
Event Emitters:
- If your application uses custom event emitters, you can leverage them for cleanup.
- Create an event like
'cleanup'
and emit it before exiting. - Listeners for this event can perform cleanup tasks.
const EventEmitter = require('events'); const myEmitter = new EventEmitter(); function cleanupHandler1() { console.log('Cleanup task 1'); } function cleanupHandler2() { console.log('Cleanup task 2'); } myEmitter.on('cleanup', cleanupHandler1); myEmitter.on('cleanup', cleanupHandler2); // Your main program logic here // Before exiting myEmitter.emit('cleanup');
Promises with
finally
:- With Node.js 10+, Promises offer a
finally
block that runs regardless of resolution (success or failure). - Use it within your asynchronous tasks to ensure cleanup even if errors occur.
const fs = require('fs').promises; async function readFile(filename) { try { const data = await fs.readFile(filename, 'utf-8'); return data; } finally { // Always close the file descriptor (assuming it exists in a variable) if (fileDescriptor) { await fs.close(fileDescriptor); } } } // Usage readFile('data.txt') .then(data => console.log(data)) .catch(err => console.error(err));
- With Node.js 10+, Promises offer a
Destructors (Experimental):
- Node.js is experimenting with destructors for cleaning up resources associated with objects.
- While not widely available yet, it's a potential future approach.
node.js