Handling container shutdowns in app code

Containers, Kubernetes

Most small apps start out running on a PaaS these days such as DigitalOcean App Platform. Platforms like these control the environment pre and post app execution. This isn't a problem when it comes to pre-execution as you can run your startup tasks when your app is started.

However, running clean up code when the app, or more specifically the container is being shutdown isn't as straightforward. This is where we can feed two birds with one slice of bread using Linux Signals.

The signal I use personally is SIGTERM -- which indicates intent to terminate the process. This signal is sent by the operating service when the client container is going to be shutdown. While you can catch this signal and prevent shutdown, most of services will send a SIGKILL signal forcing shutdown of the app after a certain time duration. In some cases this is configurable.

We feed two birds because using SIGTERM an app can:

  1. execute clean up code
  2. gracefully shutdown the application

This ensures that any operations an app is in the middle of, have some time to exit. So what does that look like?

// javascript
process.on('SIGTERM', () => {
    console.info('SIGTERM signal received.');

    /**
     * This is where cleanup code can be run. For example, closing down the http server.
     */
    console.log('Closing http server.');
    server.close(() => {
        console.log('Http server closed.');
    });

    process.exit(0)
});

This example snippet runs in a nodejs environment, attaching an anonymous function () => {...} to the process when SIGTERM signal occurs. The clean up code will run and the server which is an http server in this example, but could be any service time, is closed, and process.exit(0) is fired.

Note: Exit code 0 means the process exited successfully, any other exit code indicates an error of some type.

Further reading

Kubernetes best practices: terminating with grace is a great article which overlaps heavily with the content above with additional detail on expanding the durations and how these signals work in Kubernetes.