1.2.2 • Published 12 months ago

fastify-slow-down v1.2.2

Weekly downloads
-
License
ISC
Repository
github
Last release
12 months ago

CI

A slow down plugin for fastify

Installation

npm i fastify-slow-down

Usage

Register SlowDown as a Fastify plugin. This plugin will add an onRequest hook to slow down replies if a client (based on their IP address by default) has made too many multiple requests in the given timeWindow and it will add slowDown request decorator, which is an object with the following properties:

NameTypeDescription
limitnumberthe maximum limit until the server starts to delay the response
currentnumberthe index of the current request
remainingnumberhow many requests are left until the server starts to delay the response
delaynumber | undefinedvalue of the delay (in milliseconds) applied to this request
import Fastify from 'fastify'
import slowDownPlugin from 'fastify-slow-down'

const fastify = Fastify()

// register the plugin
fastify.register(slowDownPlugin)

// create a route
fastify.get('/', async () => 'Hello from fastify-slow-down!')

// start server
await fastify.listen({ port: 3000 })

The response will have some additional headers:

HeaderDescription
x-slow-down-limithow many requests in total the client can make until the server starts to slow down the response
x-slow-down-remaininghow many requests remain to the client in the timeWindow
x-slow-down-delayhow much delay (in milliseconds) has been applied to this request

Configuration

NameTypeDefault ValueDescription
delaystring | number1 secondBase unit of time delay applied to requests. It can be expressed in milliseconds or as string in ms format. Set to 0 to disable delaying.
delayAfternumber5number of requests received during timeWindow before starting to delay responses. Set to 0 to disable delaying.
maxDelaystring, numberInfinitythe maximum value of delay that a request has after many consecutive attempts. It is an important option for the server when it is running behind a load balancer or reverse proxy, and has a request timeout. Set to 0 to disable delaying.
timeWindowstring |, number30 secondsThe duration of the time window during which request counts are kept in memory. It can be expressed in milliseconds or as a string in ms format. Set to 0 to disable delaying.
inMemoryCacheSizenumber5000The maximum number of items that will be stored in the in-memory cache (this plugin internally uses a lru cache to handle the clients, you can change the size of the cache with this option)
redisRedis client instance from the ioredis packageundefinedby default this plugin uses an in-memory store, but if your application works on more than one server it is useless, since the data is stored locally. You can pass a Redis client here and magically the issue is solved. To achieve the maximum speed, this plugin requires the use of ioredis. Note: the default parameters of a redis connection are not the fastest to provide a slow-down. We suggest to customize the connectTimeout and maxRetriesPerRequest as in the example.
headersbooleantrueflag to add custom headers x-slow-down-limit, x-slow-down-remaining, x-slow-down-delay for all server responses.
keyGeneratorfunction(req) => req.ipFunction used to generate keys to uniquely identify requests coming from the same user
onLimitReachedfunctionundefinedFunction that gets called the first time the limit is reached within timeWindow.
skipFailedRequestsbooleanfalseWhen true, failed requests (status >= 400) won't be counted.
skipSuccessfulRequestsbooleanfalseWhen true, successful requests (status < 400) won't be counted.
skipfunctionundefinedFunction used to skip requests. Returning true from the function will skip limiting for that request.

Example with configuration

Registering the plugin with these options:

fastify.register(slowDownPlugin, {
  delay: '10 seconds',
  delayAfter: 10,
  timeWindow: '10 minutes',
  maxDelay: '100 seconds'
})

A delay specified via the delay option will be applied to requests coming from the same IP address (by default) when more than delayAfter requests are received within the time specified in the timeWindow option.

In 10 minutes the result of hitting the API will be:

  • 1st request - no delay
  • 2nd request - no delay
  • 3rd request - no delay
  • ...
  • 10th request - no delay
  • 11th request - 10 seconds delay
  • 12th request - 20 seconds delay
  • 13th request - 30 seconds delay
  • ...
  • 20th request - 100 seconds delay
  • 21st request - 100 seconds delay*

After 10 minutes without hitting the API the results will be:

  • 21th request - no delay
  • 21th request - no delay
  • ...
  • 30th request - no delay
  • 31th request - 10 seconds delay

*Delay remains the same because the value of maxDelay option is 100 seconds

Integration with fastify-rate-limit

The plugin slows down the response without stopping it at a certain limit. This can put the server in a difficult situation because the client can make many requests without waiting for a response. To limit the number of requests, it should be used together with the fastify-rate-limit plugin.

See in this example which is the implementation using fastify-slow-down and fastify-rate-limit plugins.

If the delayAfter value of the fastify-slow-down package is set to be less than the max value of the fastify-rate-limit package, then you will see the responses being delayed once the delayAfter value has been exceeded, by the number of ms as specified in the delay value.

However, once the max value from the fastify-rate-limit package has been exceeded, then as expected you will still have rate limit errors returned but they will also be delayed according to the delay value from the fastify-slow-down package assuming that the delayAfter value has also been exceeded.