loading...
Cover image for Graceful Shutdown with NodeJS and Terminus

Graceful Shutdown with NodeJS and Terminus

wakeupmh profile image Marcos Henrique ・3 min read
image credits Mattias Breitholtz

What is Graceful Shutdown? 🤠

When an application is interrupted or terminated, it can be in the middle of an operation, a request or other service for example.
Inconsistencies can happen 🤷‍♀️

Therefore, the ideal is that when an application is finished, it knows how to deal with it and finish everything in between, finish an already started request or free up resources. This is a graceful shutdown.

To do this, it is necessary to use the communication signals between processes of the operating system.

What the hell are IPC (Inter-Process Communication) signals? 😥


Do you know when you use Ctrl + C or kill with a pid to end a program in the terminal?

Essentially this sends a signal for it to be stopped/terminated, that is, you are already sending signals to processes!

Their operation is as follows:

If a signal is sent to a process, the operating system will call the routine of that process to the signal, if it does not exist, it uses the default.

Example:

if I use Ctrl + C in a program, a SIGINT signal is sent to it, if it has declared a function to handle this event, it will be called, if not, it will be used the default which is to interrupt the process.

But what about NodeJS, what does it have to do with it? 🙄

Let's practice a little, in the code below are defined 3 functions that will be called when the process receives 3 distinct signals.

So far so good right?

  • SIGTERM is the signal for termination, code 15.

  • SIGINT is the signal for interruption, for example it is the one used in Ctrl + C and has code 2.

  • SIGHUP is for reloading configuration files or terminating the terminal session, its code is 1.

This program will behave as follows: in the first three lines the functionalities will be overwritten if any of the three signals occurs, after every 6 seconds it will be written in the terminal I am running dude, this will be used to represent some work that the script would be doing.
Running the script above you can see the following result in the terminal after pressing Ctrl + C a few times on the keyboard.

^C
^C
I am running dude!

Substantially our program is receiving the signal to be interrupted using Ctrl + C.

As we define another function to be called instead of the standard one (process termination), it is being called instead, and thus putting in the int console for each SIGINT signal.

If you haven't noticed, we have just created a process that cannot be finished, either by SIGINT Ctrl + C, SIGTERM or by closing the terminal SIGHUP.

How can we kill him for good? 😟

If you want to finish the process, you will have to use the kill program.

By default it sends a signal that cannot be heard SIGKILL and that ends the process regardless of what is happening.

If you try to be rascal and try to hear the SIGKILL signal you will receive an error, as it cannot be heard.

Terminus 👽

It's incredible tool created by GoDaddy
to deal with this because it adds graceful shutdown and Kubernetes readiness/liveness checks for any HTTP applications, you can even create custom error messages.

Supports some of the most popular nodejs frameworks, such as:

  • express
  • koa
  • nodejs' core http

Example using express

import http from 'http'
import { createTerminus } from '@godaddy/terminus'
import { apiConfig } from '@api/config'
import { Logger } from '@api/infrastructure'
import { app } from '@api/server/application' //the express bootstrap goes here

const server = http.createServer(app)

const onSignal = () => {
  Logger.info('server is starting cleanup')
  return Promise.resolve()
}

const onShutdown = () => {
  Logger.info('cleanup finished, server is shutting down')
}

const onHealthCheck = () => Promise.resolve('UP')


const terminusConfiguration = Object.freeze({
  logger: Logger.info,
  signal: 'SIGINT',
  healthChecks: {
    '/healthcheck': onHealthCheck
  },
  onSignal,
  onShutdown
})

createTerminus(server, terminusConfiguration)

server.listen(apiConfig.port, () => Logger.info(`Magic happens on port ${apiConfig.port}`))

GitHub logo godaddy / terminus

Graceful shutdown and Kubernetes readiness / liveness checks for any Node.js HTTP applications



👨🏻‍💻🍻

Posted on Jun 6 by:

wakeupmh profile

Marcos Henrique

@wakeupmh

"Programming isn't about what you know; it's about what you can figure out.”

Discussion

markdown guide