fastify / under-pressure Goto Github PK
View Code? Open in Web Editor NEWMeasure process load with automatic handling of "Service Unavailable" plugin for Fastify.
License: MIT License
Measure process load with automatic handling of "Service Unavailable" plugin for Fastify.
License: MIT License
Expose a custom function to gather process metrics.
There are cases in which there's already a module/library that monitors process metrics, for example, to report to statsd
/prometeus
and similar platforms. This would allow reusing those modules for a similar task.
fastify.register(require('under-pressure'), {
maxEventLoopUtilization:0.98,
// This custom function will be bound to the fastify instance
usage() {
const { eventLoopUtilization } = this.customMetrics
return { eventLoopUtilization }
}
})
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}`)
})
There are a lot of details to figure out here, like defining a way to make sure the object returned by the custom usage
function is safe to use (i.e., it defines all the properties needed), but I just wanted to start a discussion to understand if it's something this plugin could provide.
Node v14.10.0 shipped a more precise way to check on the event loop utilization:
https://nodejs.org/api/perf_hooks.html#perf_hooks_performance_eventlooputilization_utilization1_utilization2
This module should use that if it is available.
Custom error thrown & exported from lib. Allow to override Error instance.
It's hard to distinguish if error comes from plugin, the only way is to check string message.
In fastify error handler
const { UnderPressureError } = require('under-pressure');
const errorHandler = async (err, req, reply) => {
if (err instanceof UnderPressureError) {
return sendCustomError(reply, 'Service is under pressure.', E_10000_GENERIC, SERVICE_UNAVAILABLE);
}
}
When attempting to change the log level of the status route, the option is not passed along when under-pressure builds the route.
Steps to reproduce the behavior:
fastify.register(require('under-pressure'), {
maxEventLoopDelay: 1000,
maxHeapUsedBytes: 100000000,
maxRssBytes: 100000000,
exposeStatusRoute: true,
logLevel: 'silent'
});
When hitting the ./status
route I can still see the request and response logs, which will clutter up the log files.
when setting options for the plugin, they should be forwarded to the route registration in under-pressure.
I'm happy to submit a PR to resolve the issue if required.
12.5.2
to 12.5.3
.π¨ View failing branch.
This version is covered by your current version range and after updating it in your project the build failed.
tap is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
The new version differs by 2 commits.
2233376
12.5.3
b45105f
[email protected]
See the full diff
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
Branch | Build failing π¨ |
---|---|
Dependency | tap |
Current Version | 10.7.2 |
Type | devDependency |
This version is covered by your current version range and after updating it in your project the build failed.
tap is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
The new version differs by 5 commits.
104728e
v10.7.3
352878f
Update deps
13f2ca2
Fix missing βnotβ in default message for strictNotSame
067dc57
node can be called nodejs
a335bc4
fixed punctuation in readme
See the full diff
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
In some cases you do not want to trigger the "Service Unavailable" 503 error, a very good example would be the Swagger documentation page.
Meaning there should be an option for some kind of whitelist.
Some pages or routes shouldn't be blocked, for example I would like to keep showing the Swagger Docs page, even if the healthCheck
fails for instance.
Just an proto-type idea for such an interface by introducing an option like routeWhitelist
:
fastify.register(require('@fastify/under-pressure'), {
maxEventLoopDelay: 1000,
routeWhitelist: ['/docs'],
})
An alternative solution is to provide a config option to the route config settings for under-pressure. Just like you can set a log level per route, you should be able to "ignore" the route from under-pressure plugin.
Expand the plugin's configuration options to allow the Fastify route option for exposeHeadRoute
to be set.
Happy to do the work for this if you think it's a good idea.
Kubernetes needs an endpoint that responds with a 2XX or 3XX HTTP status code to check the health of the deployed service (ref). I think it would be great to be able to re-use the under pressure endpoint for this functionality but currently this isn't possible as the Kubernetes check is a HEAD request.
fastify.register(require('under-pressure'), {
maxEventLoopDelay: 1000,
exposeStatusRoute: {
routeOpts: {
exposeHeadRoute: true,
logLevel: 'debug',
config: {
someAttr: 'value'
}
},
routeSchemaOpts: { // If you also want to set a custom route schema
hide: true
},
url: '/alive' // If you also want to set a custom route path and pass options
}
})
2.0.0
to 2.0.1
.π¨ View failing branch.
This version is covered by your current version range and after updating it in your project the build failed.
fastify is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
Fixes:
Docs:
Internals:
Dependencies:
The new version differs by 11 commits.
b456013
Bumped v2.0.1
b2bdfee
refactor: remove unnecessary condition (#1505)
3626ca9
add: @eomm as contributor (#1507)
29a77b9
Docs/fluent schema (#1485)
9398dfa
fix: unused shared schema to serializer (#1496)
563926f
add fastify-405 plugin (#1501)
cf7a096
chore(package): update fast-json-stringify to version 1.11.2 (#1500)
25ee251
Updated benchmarks (#1497)
c24b14a
Update deps (#1493)
0ff444b
Added fastify-influxdb to Community Plugins (#1472)
956c593
Updated LTS.md (#1477)
See the full diff
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
12.4.0
to 12.4.1
.π¨ View failing branch.
This version is covered by your current version range and after updating it in your project the build failed.
tap is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
The new version differs by 7 commits.
c17e6db
12.4.1
88eb85b
Ignore timers in _getActiveHandles reporting
58699d7
remove unused js-yaml from lib/tap.js
4621be8
node 11 no longer blocks process.reallyExit
74e4671
Add node 11 to travis
b074a1a
Don't use bluebird
e8fb7df
update nyc to v13
See the full diff
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
3.20.1
5.7.0
14.17.1
macOS
10.14.6 (Mojave)
In some cases, on very high load (or some time-consuming sync actions) the node's histogram.mean
can be NaN
and produce a false-negative condition that does not trigger under-pressure. In extreme cases, it can lead to node process being unresponsive.
Histogram {
min: 9223372036854776000,
max: 0,
mean: NaN,
exceeds: 0,
stddev: NaN,
percentiles: SafeMap(1) [Map] { 100 => 0 }
}
The min
value however is always present and could be used in the comparison instead. The second option is to use Infinity
to compare
Both scenarios were reproduced using autocannon
:
a) Time consuming synchronous action used in fastify route handler, e.g.:
function sleep(ms) {
const start = new Date().getTime();
const expire = start + ms;
while (new Date().getTime() < expire) { }
}
b) Big amount of connections to real-life service (500 or more in our case)
under-pressure being calculated properly and triggered
Would be nice to release 4023ba6 and 13e9781. Installing latest pulled in @fastify/error@2
into the lockfile - all other @fastify/*
deps in our project is using v3 π
I had a second look at it seems we have bugs in that part, before you even touched it.
Line 107 in 26677ab
When opts.exposeStatusRoute.routeSchemaOpts
is in Object.assign before our changes, than it means we can not overwrite the error statuscodes.
The same here:
Line 113 in 26677ab
We could set a custom error handler like this:
fastify.setErrorHandler((err, request, reply, done) => {
reply.status(err.statusCode)
.send({
code: err.code,
message: err.message
})
done()
})
a potential unit test would be:
test('check error handler', async t => {
t.plan(1)
const fastify = Fastify({ exposeStatusRoute: true })
fastify.register(underPressure, {
healthCheck: () => {
throw new Error('Arbitrary Error')
},
exposeStatusRoute: {
routeOpts: {
logLevel: 'silent'
}
}
})
t.equal((await fastify.inject().get('/').end()).body, '{"code":"FST_UNDER_PRESSURE","message":"Service Unavailable"}')
})
Originally posted by @Uzlopak in #198 (comment)
x.xx
x.xx
x.xx
Linux
xxx
Currently documentation states this:
///
Since eventLoopUtilization is only available in Node version 14.0.0 and 12.19.0 the check will be disabled in other versions.
///
I assume it actually works in 14.0.0+, not just that specific version, but documentation claims otherwise. It would be helpful to improve wording to make the intent clearer.
Documentation issue
///
Since eventLoopUtilization is only available in Node versions 12.19.0, 14.0.0, and newer, the check will be disabled in other versions.
///
I see you've already added under-pressure to the todo list for 2.0, but still: Do you expect anthing to break by just bumping the version requirement?
Line 113 in 1d8676c
Dependabot encountered the following error when parsing your .dependabot/config.yml
:
The property '#/update_configs/0/ignored_updates' of type null did not match the following type: array
Please update the config file to conform with Dependabot's specification using our docs and online validator.
setInterval will repeatedly call at the scheduled time whether or not the previous call has finished. if the server is already under load, this will likely add to the problem, because those setInterval calls will start to stack. i imagine this would be especially bad in node v8 with setInterval(..., 5ms).
for node >= v10.2.0, using setTimeout and timer.refresh would avoid this issue. i swapped it in and tests pass in node v14, at least:
const timer = setTimeout(() => {
updateMemoryUsage()
timer.refresh()
}, sampleInterval)
No response
Is custom healthCheck called after checking under pressure?
If no - we need In addition to the Db and Redis state, to know if the service is under pressure in order to form the correct answer.
Allow healthCheck
to return a custom response that will override the default { status: 'ok'}
response.
Sometime the "status" or "health" endpoints are used to return multiple informations about the system status: db connection, external services, etc. .
In the above scenario, having just a { status: 'ok' }
may not be enough.
ie:
{
status: 'ok',
db: 'ok',
externalService: 'ko',
externalService2: 'ok',
...
}
Give the user the option to change the default state of the health-check to be healthy. Meaning in case of a new deployment, the server can be reached directly if needed, without waiting on the healthCheckInterval
.
I run the server with cluster support, and I want to increase the healthCheckInterval
to reduce the load for health checks on my database. However, increasing the internal will cause 503 to be present for longer during start-up.
Introducing a new option for example, like: healthCheckDefaultHealthy
(default value is false
to be backwards compatible):
{
maxEventLoopDelay: 1000,
healthCheckDefaultHealthy: true
}
12.12.8
to 12.12.9
.π¨ View failing branch.
This version is covered by your current version range and after updating it in your project the build failed.
@types/node is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
3.28.0
5.8.1
18.0.0
Windows
10.β06.β2020
.register(underPressurePligin, {
exposeStatusRoute: {
routeOpts: {
logLevel: 'debug',
},
url: '/alive',
},
healthCheck: async function (fastifyInstance) {
// do some magic to check if your db connection is healthy, etc...
return true;
},
})
the contents of the log after executing the request
{
"level": "info",
"time": 1651439672804,
"instance": "unknown:3000",
"version": "1.0.0",
"reqId": "req-1",
"req": {
"method": "GET",
"url": "/alive",
"path": "/alive",
"parameters": {},
},
"msg": "incoming request"
}
log level is info
instead of debug
setup server with under-pressure
plugin with above config an run
expected loglevel for status route to be as defined in config
Breaking fastify server!
The main purpose of [under-pressure][1] plugin is to protect the server against the high load. I created a fake load using [autocannon][2] and the server suddenly starts throwing this error:
<--- JS stacktrace --->
==== JS stack trace =========================================
0: ExitFrame [pc: 00007FF7D342A9AC]
Security context: 0x01b3e02408d1 <JSObject>
1: _write [000001EBE7CBA7B1] [_stream_transform.js:~169] [pc=000002737CBBD07D](this=0x02fe03573099 <LineStream map = 00000149AA79E209>,0x00f819d83789 <Uint8Array map = 000002F9BBE3F279>,0x00c0496035d9 <String[#6]: buffer>,0x02fe03575639 <JSBoundFunction (BoundTargetFunction 000003C5D37BC781)>)
2: ondata [000002FE03577FC9] [_stream_readable.js:~712]...
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
1: 00007FF7D28A363F napi_wrap+128063
2: 00007FF7D2842836 v8::base::CPU::has_sse+35142
3: 00007FF7D28434F6 v8::base::CPU::has_sse+38406
4: 00007FF7D3059F4E v8::Isolate::ReportExternalAllocationLimitReached+94
5: 00007FF7D3042021 v8::SharedArrayBuffer::Externalize+833
6: 00007FF7D2F0E57C v8::internal::Heap::EphemeronKeyWriteBarrierFromCode+1436
7: 00007FF7D2F197D0 v8::internal::Heap::ProtectUnprotectedMemoryChunks+1312
8: 00007FF7D2F162F4 v8::internal::Heap::PageFlagsAreConsistent+3204
9: 00007FF7D2F0BB13 v8::internal::Heap::CollectGarbage+1283
10: 00007FF7D2F0A184 v8::internal::Heap::AddRetainedMap+2452
11: 00007FF7D2F31E1F v8::internal::Factory::NewRawTwoByteString+95
12: 00007FF7D2F349CB v8::internal::Factory::NewStringFromUtf8+187
13: 00007FF7D305681A v8::String::NewFromUtf8+298
14: 00007FF7D27A9ABF node::tracing::TraceEventHelper::SetAgent+40751
15: 00007FF7D285A46D v8::internal::Malloced::operator delete+1661
16: 00007FF7D342A9AC v8::internal::SetupIsolateDelegate::SetupHeap+45852
17: 000002737CBBD07D
Steps to reproduce the behavior:
fastify.register(require('under-pressure') , {
maxEventLoopDelay: 0,
maxHeapUsedBytes: 0,
maxRssBytes: 0
})
console.log(fastify.memoryUsage())
The very fastify plugin which is supposed to protect against load is breaking the fastify server, need some help with another plugin or some other way to implement load protection
Cross posted on Stackoverflow: https://stackoverflow.com/q/64137079/2404470
1.4.0
to 1.5.0
.π¨ View failing branch.
This version is covered by your current version range and after updating it in your project the build failed.
fastify-plugin is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.
The new version differs by 3 commits.
e2d6f1f
Bumped v1.5.0
caff3e9
fn.default check for transpiled modules (#61)
31708bb
Add tests for dependency graph checking (#58)
See the full diff
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
12.5.0
to 12.5.1
.π¨ View failing branch.
This version is covered by your current version range and after updating it in your project the build failed.
tap is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.
The new version differs by 4 commits.
d03f383
12.5.1
2816d28
Ignore esm in stack output
7daf018
do not run browser test in node v6
a51cc6f
run test: load tap from full module location
See the full diff
There is a collection of frequently asked questions. If those donβt help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot π΄
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.