-
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from fastify/init
Initial
- Loading branch information
Showing
6 changed files
with
460 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
language: node_js | ||
|
||
node_js: | ||
- "8" | ||
- "6" | ||
- "4" | ||
|
||
notifications: | ||
email: | ||
on_success: never | ||
on_failure: always |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,68 @@ | ||
# under-pressure | ||
Automatic handling of "Service Unavailable" plugin | ||
|
||
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/) | ||
[![Build Status](https://travis-ci.org/fastify/under-pressure.svg?branch=master)](https://travis-ci.org/fastify/under-pressure) | ||
|
||
Measure process load with automatic handling of *"Service Unavailable"* plugin for Fastify. | ||
It can check `maxEventLoopDelay`, `maxHeapUsedBytes` and `maxRssBytes` values. | ||
|
||
<a name="install"></a> | ||
## Install | ||
``` | ||
npm i under-pressure --save | ||
``` | ||
|
||
<a name="usage"></a> | ||
## Usage | ||
Require the plugin and register it into the Fastify instance. | ||
```js | ||
const fastify = require('fastify')() | ||
|
||
fastify.register(require('under-pressure'), { | ||
maxEventLoopDelay: 1000, | ||
maxHeapUsedBytes: 100000000, | ||
maxRssBytes: 100000000 | ||
}) | ||
|
||
fastify.get('/', (req, reply) => { | ||
reply.send({ hello: 'world'}) | ||
}) | ||
|
||
fastify.listen(3000, err => { | ||
if (err) throw err | ||
console.log(`server listening on ${fastify.server.address().port}`) | ||
}) | ||
``` | ||
`under-pressure` will automatically handle for you the `Service Unavailable` error once one of the thresholds has been reached. | ||
You can configure the error message and the `Retry-After` header. | ||
```js | ||
fastify.register(require('under-pressure'), { | ||
maxEventLoopDelay: 1000, | ||
message: 'Under pressure!', | ||
retryAfter: 50 | ||
}) | ||
``` | ||
|
||
The default value for `maxEventLoopDelay`, `maxHeapUsedBytes` and `maxRssBytes` is `0`. | ||
If the value is `0` the check will not be performed. | ||
|
||
Thanks to the encapsulation model of Fastify, you can selectively use this plugin in some subset of routes or even with different thresholds in different plugins. | ||
|
||
#### `memoryUsage` | ||
This plugin also exposes a function that will tell you the current values of `heapUsed`, `rssBytes` and `eventLoopDelay`. | ||
```js | ||
console.log(fastify.memoryUsage()) | ||
``` | ||
|
||
#### Status route | ||
If needed you can pass `{ exposeStatusRoute: true }` and `under-pressure` will expose a `/status` route for you that sends back a `{ status: 'ok' }` object. This can be useful if you need to attach the server to an ELB on AWS for example. | ||
|
||
<a name="acknowledgements"></a> | ||
## Acknowledgements | ||
|
||
This project is kindly sponsored by [LetzDoIt](http://www.letzdoitapp.com/). | ||
|
||
<a name="license"></a> | ||
## License | ||
|
||
Licensed under [MIT](./LICENSE). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
'use strict' | ||
|
||
const fp = require('fastify-plugin') | ||
|
||
function underPressure (fastify, opts, next) { | ||
opts = opts || {} | ||
|
||
const sampleInterval = opts.sampleInterval || 5 | ||
const maxEventLoopDelay = opts.maxEventLoopDelay || 0 | ||
const maxHeapUsedBytes = opts.maxHeapUsedBytes || 0 | ||
const maxRssBytes = opts.maxRssBytes || 0 | ||
|
||
const checkMaxEventLoopDelay = maxEventLoopDelay > 0 | ||
const checkMaxHeapUsedBytes = maxHeapUsedBytes > 0 | ||
const checkMaxRssBytes = maxRssBytes > 0 | ||
|
||
var heapUsed = 0 | ||
var rssBytes = 0 | ||
var eventLoopDelay = 0 | ||
var lastCheck = now() | ||
const timer = setInterval(updateMemoryUsage, sampleInterval) | ||
|
||
fastify.decorate('memoryUsage', memoryUsage) | ||
fastify.addHook('onClose', onClose) | ||
|
||
if (opts.exposeStatusRoute === true) { | ||
fastify.route({ | ||
url: '/status', | ||
method: 'GET', | ||
schema: { | ||
response: { 200: { | ||
type: 'object', | ||
properties: { | ||
status: { type: 'string' } | ||
}} | ||
} | ||
}, | ||
handler: onStatus | ||
}) | ||
} | ||
|
||
if (checkMaxEventLoopDelay === false && | ||
checkMaxHeapUsedBytes === false && | ||
checkMaxRssBytes === false) { | ||
return next() | ||
} | ||
|
||
const serviceUnavailableError = new Error(opts.message || 'Service Unavailable') | ||
const retryAfter = opts.retryAfter || 10 | ||
|
||
fastify.addHook('onRequest', onRequest) | ||
|
||
function updateMemoryUsage () { | ||
var mem = process.memoryUsage() | ||
heapUsed = mem.heapUsed | ||
rssBytes = mem.rss | ||
var toCheck = now() | ||
eventLoopDelay = toCheck - lastCheck - sampleInterval | ||
lastCheck = toCheck | ||
} | ||
|
||
function onRequest (req, res, next) { | ||
if (checkMaxEventLoopDelay && eventLoopDelay > maxEventLoopDelay) { | ||
sendError(res, next) | ||
return | ||
} | ||
|
||
if (checkMaxHeapUsedBytes && heapUsed > maxHeapUsedBytes) { | ||
sendError(res, next) | ||
return | ||
} | ||
|
||
if (checkMaxRssBytes && rssBytes > maxRssBytes) { | ||
sendError(res, next) | ||
return | ||
} | ||
|
||
next() | ||
} | ||
|
||
function sendError (res, next) { | ||
res.statusCode = 503 | ||
res.setHeader('Retry-After', retryAfter) | ||
next(serviceUnavailableError) | ||
} | ||
|
||
function memoryUsage () { | ||
return { | ||
eventLoopDelay, | ||
rssBytes, | ||
heapUsed | ||
} | ||
} | ||
|
||
function onStatus (req, reply) { | ||
reply.send({ status: 'ok' }) | ||
} | ||
|
||
function onClose (fastify, done) { | ||
clearInterval(timer) | ||
done() | ||
} | ||
|
||
next() | ||
} | ||
|
||
function now () { | ||
var ts = process.hrtime() | ||
return (ts[0] * 1e3) + (ts[1] / 1e6) | ||
} | ||
|
||
module.exports = fp(underPressure, '>=0.27.0') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"name": "under-pressure", | ||
"version": "0.1.0", | ||
"description": "Measure process load with automatic handling of 'Service Unavailable' plugin for Fastify.", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "standard && tap test.js" | ||
}, | ||
"keywords": [ | ||
"fastify", | ||
"service unavailable", | ||
"limit", | ||
"delay", | ||
"retry" | ||
], | ||
"author": "Tomas Della Vedova - @delvedor (http://delved.org)", | ||
"license": "MIT", | ||
"dependencies": { | ||
"fastify-plugin": "^0.1.1" | ||
}, | ||
"devDependencies": { | ||
"fastify": "^0.31.0", | ||
"simple-get": "^2.7.0", | ||
"standard": "^10.0.3", | ||
"tap": "^10.7.2" | ||
} | ||
} |
Oops, something went wrong.