2.3.0 • Published 2 years ago

@mangosteen/background-healthcheck v2.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

background-healthcheck

Node.js package designed to provide healthchecking to containerized background tasks.

Installation

With npm do:

$ npm install @mangosteen/background-healthcheck

Then, create a file healthcheck.js:

import { healthcheck } from '@mangosteen/background-healthcheck';

healthcheck(10000).then(process.exit);

The value 10000 is a staleInterval param. If you signal heartbeat less often than staleInterval, the container will be reported as unhealthy.

The next step is to configure your Dockerfile:

HEALTHCHECK --interval=15s --retries=3 --timeout=5s \
    CMD ["node", "healthcheck.js"]

If you use AWS ECS, then keep in mind ECS ignores Dockerfile's HEALTHCHECK. You need to put the healthcheck command in task definition. Similarly, Kubernetes ignores Dockerfile's HEALTHCHECK too, and provides an alternative way to check health. However, you can use our library in either case.

Usage in your task's code

The healthcheck process checks if the heartbeat has been signaled recently. If you do not signal heartbeat periodically, the healthcheck will report your container as unhealthy. Pay special attention to async functions that take a long time to complete.

To begin, create a new ModuleHeartbeat instance:

import { ModuleHeartbeat } from '@mangosteen/background-healthcheck';

const appModule = new ModuleHeartbeat('app', 2000);

This creates a new heartbeat module. In this example, the module represents the entire app and we assume this will be the only module you use in the entire app. Alternativaly, if your app has multiple submodules that you would like to healthcheck more granuarly, you can create an arbitrary number of modules in your app. If any module becomes unhealthy, the entire app is considered unhealthy.

The ModuleHeartbeat constructor accepts two arguments:

  • moduleName
    Optional arbitrary string that identifies the module. Two module instances with the same name are interchangeable.
    Default: globally-unique randomly generated name (256-bit entropy)
  • interval
    Optional number of milliseconds limiting the frequency at which the heartbeat is reported (to reduce disk I/O).
    Default: 2000

To signal a heartbeat, just call the signal method of a module:

for (let i = 0; i < 1000; i++) {
    await insertRowsBatchToDb();
    await appModule.signal();
}

If you want to signal a heartbeat during a long-running network request, and you cannot add calls to signal at more granular level, you can use signalWhile to issue heartbeats periodically:

const action: PromiseLike<T> = ....

const actionResult: T = await appModule.signalWhile(
    action,
    30000,
);

This code will signal heartbeats during the first 30.000ms or until the action promise resolves, whichever happens earlier.

If you are processing streams in a pipeline, you can also signal heartbeat automatically as chunks are processed using createHeartbeatStream transform stream:

import { createHeartbeatStream, ModuleHeartbeat } from '@mangosteen/background-healthcheck';
import stream from 'stream';
import fs from 'fs';
import { promisify } from 'util';

const pipeline = promisify(stream.pipeline);
const appModule = new ModuleHeartbeat();

(async () => {
    await pipeline(
        fs.createReadStream('./shakespeare.txt'),
        createHeartbeatStream({ heartbeat: appModule }),
        createSinkStream(),
    );
})();

function createSinkStream(): stream.Writable {
    return new stream.Writable({
        highWaterMark: 0,
        write(chunk, _encoding, callback): void {
            callback();
        },
    });
}

What is it good for?

Imagine running a Docker task in AWS Elastic Container Service, on EC2 or Fargate. This task is not a server, but rather a data retrieval / transformation task. It loads data from some data source (like an API or a DB), manipulates it in some way (maybe resizes an image?), then writes the result somewhere. Wouldn't it be nice to still be able to determine if such a container is healthy? That's what this package is for.

Reference

1.3.1

2 years ago

2.3.0

2 years ago

2.2.0

2 years ago

2.1.1

2 years ago

2.1.0

2 years ago

2.0.0

2 years ago

1.3.0

3 years ago

1.2.0

3 years ago

1.1.0

3 years ago

1.0.3

3 years ago

1.0.2

3 years ago

1.0.1

3 years ago

1.0.0

3 years ago