Install @fastify/under-pressure
mainInstall the plugin using npm:
npm i @fastify/under-pressurerepository·main·Indexed 19 days ago
https://github.com/fastify/under-pressureA process load measuring plugin for Fastify that monitors system resources—including event loop delay, heap usage, RSS memory, and event loop utilization—and automatically handles 'Service Unavailable' responses when thresholds are exceeded. It provides tools for custom pressure handlers, health check functions, a status route for load balancers, and methods like fastify.isUnderPressure() and fastify.memoryUsage() to inspect system state.
Install the plugin using npm:
npm i @fastify/under-pressureYou can enable a /status route (or a custom path) that returns { status: 'ok' }. This is useful for load balancers like AWS ELB.
To customize the route, use the exposeStatusRoute option. You can provide an object to configure routeOpts (Fastify route options), routeSchemaOpts (request schema), routeResponseSchemaOpts (to merge custom response fields), and url (the path).
fastify.register(require('@fastify/under-pressure'), {
maxEventLoopDelay: 1000,
exposeStatusRoute: {
routeOpts: {
logLevel: 'debug',
config: {
someAttr: 'value'
}
},
routeSchemaOpts: {
hide: true
},
url: '/alive'
}
})Register @fastify/under-pressure to monitor system resources. You can set thresholds for event loop delay, heap usage, RSS memory, and event loop utilization.
If a threshold is set to 0 (the default), that specific check is disabled. When a threshold is exceeded, the plugin automatically handles the request by returning a Service Unavailable error. You can customize the error message and the retryAfter (in seconds) header.
const fastify = require('fastify')()
fastify.register(require('@fastify/under-pressure'), {
maxEventLoopDelay: 1000,
maxHeapUsedBytes: 100000000,
maxRssBytes: 100000000,
maxEventLoopUtilization: 0.98,
message: 'Under pressure!',
retryAfter: 50
})Use the sampleInterval option (in milliseconds) to set how often metrics are sampled.
Note: The default value varies by Node.js version. In Node 8 and 10, it is 5ms; in Node 11.10.0 and above, it is 1000ms due to the availability of monitorEventLoopDelay.
fastify.register(require('@fastify/under-pressure'), {
sampleInterval: 500
})You can check the current pressure status within your route handlers using fastify.isUnderPressure(). This is useful for skipping complex computations or non-essential tasks when the system is under load.
fastify.get('/', (request, reply) => {
if (fastify.isUnderPressure()) {
// skip complex computation
}
reply.send({ hello: 'world'})
})To include extra information (like database status or custom metrics) in the status route response, implement the healthCheck function and use routeResponseSchemaOpts to define the schema for the additional fields. Note that the status field will always be present.
fastify.register(underPressure, {
exposeStatusRoute: {
routeResponseSchemaOpts: {
extraValue: { type: 'string' },
metrics: {
type: 'object',
properties: {
eventLoopDelay: { type: 'number' },
rssBytes: { type: 'number' },
heapUsed: { type: 'number' },
eventLoopUtilized: { type: 'number' },
},
},
}
},
healthCheck: async (fastifyInstance) => {
return {
extraValue: await getExtraValue(),
metrics: fastifyInstance.memoryUsage(),
}
},
})Instead of the default Service Unavailable response, you can provide a pressureHandler function. This allows you to log the specific reason for the pressure (the type and value) and decide how to respond to the client.
If the handler does not call reply.send(), the request will proceed normally. The handler can be defined globally during registration or specifically for a single route via the route config object.
const fastify = require('fastify')()
const underPressure = require('@fastify/under-pressure')()
fastify.register(underPressure, {
maxHeapUsedBytes: 100000000,
pressureHandler: (request, reply, type, value) => {
if (type === underPressure.TYPE_HEAP_USED_BYTES) {
fastify.log.warn(`too many heap bytes used: ${value}`)
} else if (type === underPressure.TYPE_RSS_BYTES) {
fastify.log.warn(`too many rss bytes used: ${value}`)
}
reply.send('out of memory')
}
})The plugin exposes a fastify.memoryUsage() method that returns the current values for heapUsed, rssBytes, eventLoopDelay, and eventLoopUtilized.
console.log(fastify.memoryUsage())The healthCheck property accepts an async function used to verify external resources (e.g., database connectivity).
boolean or an object.true.healthCheckInterval in ms) or every time the status route is called.fastify.register(require('@fastify/under-pressure'), {
healthCheck: async function (fastifyInstance) {
// Check if db connection is healthy
return true
},
healthCheckInterval: 500
})By default, the plugin throws a standard error when thresholds are met. You can provide a customError class to change the error type thrown.
class CustomError extends Error {
constructor () {
super('Custom error message')
Error.captureStackTrace(this, CustomError)
}
}
fastify.register(require('@fastify/under-pressure'), {
maxEventLoopDelay: 1000,
customError: CustomError
})You can expose a GET route that returns the current health status of the service. This is useful for load balancers or orchestrators (like Kubernetes).
exposeStatusRoute can be:
string: The URL path (e.g., '/status').object: Allows customizing the route.Object properties:
url: The path for the route.routeOpts: Standard Fastify route options (e.g., prefix, schema).routeSchemaOpts: Customization for the response schema.routeResponseSchemaOpts: Customization for the properties of the successful response object.fastify.register(require('@fastify/under-pressure'), {
exposeStatusRoute: {
url: '/health',
routeOpts: {
schema: { /* ... */ }
}
}
})Register @fastify/under-pressure to monitor system resources (Event Loop delay, Heap usage, RSS, and Event Loop Utilization) and external health checks. When thresholds are exceeded, the plugin can automatically reject requests with a 503 Service Unavailable error or trigger a custom pressureHandler.
| Option | Type | Default | Description |
|---|---|---|---|
sampleInterval | number | 1000 | Interval in milliseconds to sample memory and event loop metrics. |
maxEventLoopDelay | number | 0 | Maximum allowed event loop delay in milliseconds. |
maxHeapUsedBytes | number | 0 | Maximum allowed heap used in bytes. |
maxRssBytes | number | 0 | Maximum allowed RSS (Resident Set Size) in bytes. |
maxEventLoopUtilization | number | 0 | Maximum allowed event loop utilization (0 to 1). |
healthCheck | function | false | An async function (fastify) => Promise<boolean> to check external dependencies. |
healthCheckInterval | number | -1 | How often to run the healthCheck in milliseconds. |
customError | Error | FST_UNDER_PRESSURE | A custom error object to throw when pressure is detected. |
message | string | 'Service Unavailable' | Custom error message if customError is not provided. |
pressureHandler | function | undefined | A custom function to handle pressure. Receives (req, reply, type, value). |
retryAfter | number | 10 | Seconds to set in the Retry-After header when using the default handler. |
exposeStatusRoute | object | string | false | Configuration to expose a GET route for health status. See Expose Status Route. |
If you provide a pressureHandler, it is called when any threshold is exceeded. The type parameter will be one of the following constants:
TYPE_EVENT_LOOP_DELAYTYPE_HEAP_USED_BYTESTYPE_RSS_BYTESTYPE_HEALTH_CHECKTYPE_EVENT_LOOP_UTILIZATIONconst fastify = require('fastify')()
fastify.register(require('@fastify/under-pressure'), {
maxHeapUsedBytes: 100 * 1024 * 1024, // 100MB
maxEventLoopDelay: 100,
healthCheck: async (fastify) => {
// check database connection, etc.
return true
}
})