2.2.0 • Published 11 months ago

happy-feet v2.2.0

Weekly downloads
10
License
MIT
Repository
github
Last release
11 months ago

Happy Feet

Application state management with triggers that span both urgent and non-urgent states to account for more graceful and staggered recoveries.

State Management

Sometimes healthy isn't so straight forward. Intermediate states can help fill the void.

const happy = require('happy-feet')();

// by default, happy.state === happy.STATE.HAPPY

// sometimes apps want to differentiate between unhealthy, and not-yet-healthy...
happy.state = happy.STATE.STARTING;

// app is now running
happy.state = happy.STATE.HAPPY;

// something went wrong, but we're still operational.
// eventual escalation to UNHAPPY
happy.state = happy.STATE.WARN;

// other times, maybe you just want your own custom state -- who are we to judge?
happy.state = 'BLACK_HOLE';

// DANGER WILL ROBINSON!
happy.state = happy.STATE.UNHAPPY;

// once state set to UNHAPPY it is irreversible, future states will be ignored

Usage

The core functionality of happy-feet lies in setting the state property of your happy-feet instance. This state may be set automatically by happy-feet as it monitors your process or set by your application. The value of this state can be automatically reflected at a web service URL via one of the provided middlewares. This can be used to signal to supervising processes that are monitoring this health indicator when they need to take corrective action.

You may also decide to manually use the happy-feet API to roll your own state management logic:

const happy = require('happy-feet')({ /* optional options */ });

// happy.state === happy.STATE.HAPPY by default

if (happy.state !== happy.STATE.HAPPY) {
  // do something about it
}

There are three built-in values that have a special meaning to happy-feet:

StateMeaning
happy.STATE.HAPPYThis indicates that your service is in a healthy state
happy.STATE.WARNThis means your service is having problems. The health check page will reflect an OK status, but eventually the state will automatically transition to UNHAPPY.
happy.STATE.UNHAPPYThis signals that your service instance should be considered ready to be terminated/restarted due to being in a bad state.

You can also use custom states if you're rolling your own health status implementation.

Automatic state change triggers include soft and hard limits. Soft limits trigger a warning state (a temporary successful state) indicating the eventual need to be restarted, while hard limits trigger a state of immediate urgency.

The automatic transition from the WARN state to UNHAPPY is done after a random amount of time, which is configurable with the escalationSoftLimitMin and escalationSoftLimitMax settings. The purpose of this randomness is to avoid each member of a service cluster being taken down at the same time in case of full cluster impacting faults.

Here's a full list of configuration options for happy-feet:

OptionTypeDefaultInfo
escalationSoftLimitMinnumber60Minimum time (in seconds) before a WARN state may be escalated to an UNHAPPY state.
escalationSoftLimitMaxnumber600Maximum time (in seconds) before a WARN state may be escalated to an UNHAPPY state.
uncaughtExceptionSoftLimitnumber1Number of uncaught exceptions before WARN state.
uncaughtExceptionHardLimitnumberundefinedNumber of uncaught exceptions before UNHAPPY state. Disabled by default.
unhandledRejectionSoftLimitnumberundefinedNumber of unhandled rejections before WARN state. Disabled by default.
unhandledRejectionHardLimitnumberundefinedNumber of unhandled rejections before UNHAPPY state. Disabled by default.
rssSoftLimitnumberundefinedMemory Resident Set Size (in bytes) before WARN state. Disabled by default.
rssHardLimitnumberundefinedMemory Resident Set Size (in bytes) before UNHAPPY state. Disabled by default.
heapSoftLimitnumberundefinedTotal heap size (in bytes) before WARN state. Disabled by default.
heapHardLimitnumberundefinedTotal heap size (in bytes) before UNHAPPY state. Disabled by default.
eventLoopSoftLimitnumberundefinedEvent Loop delay (in ms) before WARN state. Disabled by default. Recommended value of 150 or higher.
eventLoopHardLimitnumberundefinedEvent Loop delay (in ms) before UNHAPPY state. Disabled by default. Recommended value of 500 or higher.
timeLimitMinnumberundefinedMinimum time (in seconds) before UNHAPPY state. Disabled by default. Useful for periodic application restarts. Both timeLimitMin and timeLimitMax must be set to use this feature.
timeLimitMaxnumberundefinedMaximum time (in seconds) before UNHAPPY state. Disabled by default. Useful for periodic application restarts. Both timeLimitMin and timeLimitMax must be set to use this feature.
logger{ warn,error }consoleLogging interface to use when state changes occur. Defaults to use console.
gracePeriodnumber300 (5 mins)The time (in seconds) before any thresholds can trigger an unhealthy state change to alleviate startup pains
logOnUnhappybooleantrueIf enabled, all checks for state will be logged if NOT HAPPY to help troubleshoot state changes

A happy-feet instance has this interface:

PropertyTypeInfo
statestringGet/set the current state of your process.
updateState(state, reason, code)functionCalling this does the same thing as setting the state property, except it allows you to log a reason for the change. The code argument is there to enable identifying the reason for transitions programmatically (see events below).
destroy()functionUse this to free the instance.

Additionally, each happy-feet instance is an EventEmitter. It emits a change event with the following parameters whenever its state changes:

ParameterTypeInfo
statestringThe new state
reasonstringThe textual description of the change
codestringCan be any value for custom implementations or manual if the state was changed through assignment. For automatic transitions can be one of the following: uncaughtExceptions, unhandledRejections, memory, eventLoop, or escalation

Connect Usage

If you've already got an (Connect) API, attach a handler like so:

const happyConnect = require('happy-feet/connect');
const handler = happyConnect({ /* options */ }, { /* optional happy options */ });

app.use(handler);

// Manually change the state
handler.happy.state = handler.happy.STATE.WARN; 
OptionTypeDefaultInfo
urlstring"/_health"Route to return health status. Defaults to common Kubernetes healthcheck route.
methodstring"GET"Method required to return health status.
errorStatusnumber500Status code returned if in UNHAPPY state.
statusobject{}A collection of custom overrides for status responses based on individual states.
statusSTATE.statusCodenumber200|500Status code returned for the given state. By default ${errorStatus} is returned for UNHAPPY state, otherwise 200.
statusSTATE.bodystring${STATE}Body message returned for the given state. By default ${STATE} will be returned verbatim.
statusSTATE.contentTypestringtext/plainContent type to respond with.
Return PropertyTypeInfo
happyHappyInstance of Happy.

Express Usage

If you've already got an (Express) API, attach a handler like so:

const happyExpress = require('happy-feet/express');

const handler = happyExpress({ /* options */ }, { /* optional happy options */ });
app.get('/_health', handler);

// Manually change the state
handler.happy.state = handler.happy.STATE.WARN; 
OptionTypeDefaultInfo
errorStatusnumber500Status code returned if in UNHAPPY state.
statusobject{}A collection of custom overrides for status responses based on individual states.
statusSTATE.statusCodenumber200|500Status code returned for the given state. By default ${errorStatus} is returned for UNHAPPY state, otherwise 200.
statusSTATE.bodystring${STATE}Body message returned for the given state. By default ${STATE} will be returned verbatim.
statusSTATE.contentTypestringtext/plainContent type to respond with.
Return PropertyTypeInfo
happyHappyInstance of Happy.

API Usage

Or if your service does not expose an API, you can use this helper to expose your healthcheck for you.

const happyApi = require('happy-feet/api');

const handler = happyApi({ /* options */ }, { /* optional happy options */ });
OptionTypeDefaultInfo
port'number'80HTTP port to bind to.
urlstring"/_health"Route to return health status. Defaults to common Kubernetes healthcheck route.
methodstring"GET"Method required to return health status.
errorStatusnumber500Status code returned if in UNHAPPY state.
statusobject{}A collection of custom overrides for status responses based on individual states.
statusSTATE.statusCodenumber200|500Status code returned for the given state. By default ${errorStatus} is returned for UNHAPPY state, otherwise 200.
statusSTATE.bodystring${STATE}Body message returned for the given state. By default ${STATE} will be returned verbatim.
statusSTATE.contentTypestringtext/planContent type to responde with.
Return PropertyTypeInfo
happyHappyInstance of Happy.
serverhttp.ServerInstance of http.Server.

Advanced Healthchecks

The main advantage of Advanced Healthchecks over the default escalation threshold is that a centralized system can coordinate restarts in a more graceful and controlled manner without impact to availability.

If your system for monitoring healthchecks is capable of discerning between catastrophic (remove from LB immediately) and unhealthy (some undesirable event or threshold, operational but eventually should be restarted), happy.STATE.WARN (HTTP statusMessage of WARN) can be leveraged to gracefully handle rolling restarts in whatever fashion deemed acceptable. By default, WARN states will be automatically escalated to UNHAPPY after a period of time to avoid vulnerabilities resulting in mass concurrent crashes and ultimately impact to customers and availability of your services.

2.2.0

11 months ago

2.1.0

1 year ago

2.0.1

1 year ago

2.0.0

2 years ago

1.6.0

4 years ago

1.5.0

4 years ago

1.4.0

4 years ago

1.3.3

4 years ago

1.3.2

4 years ago

1.3.1

5 years ago

1.3.0

5 years ago

1.2.0

7 years ago

1.1.0

7 years ago

1.0.1

7 years ago

1.0.0

7 years ago