0 votes
in NodeJS Essentials by
Explain Graceful shutdown with example in a Node.js application

1 Answer

0 votes
by

you need to listen for the SIGTERM signal and catch it:

1. Handle process kill signal

First let’s understand what is a process signal.

A signal is an asynchronous notification sent to a process or to a specific thread to notify an event that occurred.

Signal events will be emitted when the NodeJS process receives a signal.

Each signal have name(i.e. 'SIGINT', 'SIGTERM', etc.).

'SIGINT' generated with +C in the terminal.

The 'SIGTERM' signal is a generic signal used to cause program termination. Unlike 'SIGKILL', this signal can be blocked, handled, and ignored. It is the normal way to politely ask a program to terminate.

The shell command kill generates 'SIGTERM' by default.

You can read more about Termination Signals [here](https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html.

As you guess we need to add handler which will receive 'SIGTERM' signal.

Here we have a simple server which has a route that creates user in MongoDB. And the code of graceful shutdown

mongoose.connect(
  "mongodb://localhost/test",
  err => {
    if (err) throw err;
    console.log("Mongoose connected!");
  }
);
const User = mongoose.model("User", { name: String });

app.post("/user", async (req, res) => {
  try {
    const user = new User({ name: req.body.username });
    await user.save();
    res.send("Success!").status(201);
  } catch (err) {
    res.send(err.message).status(500);
  }
});

const server = app.listen(3000, () =>
  console.log("Example app listening on port 3000!")
);

process.on("SIGTERM", () => {
  console.info("SIGTERM signal received.");
  console.log("Closing http server.");
  server.close(() => {
    console.log("Http server closed.");
    // boolean means [force], see in mongoose doc
    mongoose.connection.close(false, () => {
      console.log("MongoDb connection closed.");
      process.exit(0);
    });
  });
});

2. Stop new requests from client

Now we need to stop http server and stop accepting new requests. It can be done using server.close function

3. Close all data process

As you have seen our application exits ( generated with 'SIGTERM' event ) will also close database connection.

What is the cause? - EventLoop

As we know NodeJS will exit when EventLoop queue is empty and nothing left to do.

But sometime your application can have more functions and will not exit automatically, in this point comes our last work to do. We need to exit from process using process.exit function.

Argument 0 means exit with a “success” code. To exit with a “failure” code use 1.

By default NodeJS exits with process code 0 if EventLoop is empty.

Second Implementation

My config.js file as below

const mongoose = require("mongoose");

module.exports = {
  database: process.env.MONGO_DB,

  options: {
    reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect
    reconnectInterval: 1000, // Reconnect every 500ms
    poolSize: 10 // Maintain up to 10 socket connections
  },

  // Connect connection with MongoDB Database
  connectDB: function() {
    mongoose.connect(
      this.database,
      this.options
    );
  },

  // Disconnect connection with MongoDB Database
  disconnectDB: function() {
    mongoose.disconnect(this.database);
  }
};
// on mongo connection open event print a console statement
mongoose.connection.on("open", function() {
  console.log("Connected to Database (MongoDB) ");
});

// on mongo connection error event
mongoose.connection.on("error", function() {
  console.log("error in Database (MongoDB) connections");
});

// on mongo connection disconnected event
mongoose.connection.on("disconnected", () => {
  console.log("Mongoose default connection disconnected");
});

//listen for SIGINT event(generated with <Ctrl>+C in the terminal) and close db connection on that event
process.on("SIGINT", () => {
  mongoose.connection.close(() => {
    console.log("Mongoose disconnected through app termination");
    process.exit(0);
  });
});

And then my main server.js / index.js file will have this small graceful shutdown code. Where I will listen for SIGINT event(generated with +C in the terminal) and close db connection on that event

const config = require("./config/config");

process.on("SIGINT", () => {
  config.disconnectDB();
  process.exit(0);
});
...