npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fastify-slow-down

v2.0.1

Published

A slow down plugin for fastify

Downloads

146

Readme

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:

| Name | Type | Description | | --------- | ------------------- | ------------------------------------------------------------------------ | | limit | number | the maximum limit until the server starts to delay the response | | current | number | the index of the current request | | remaining | number | how many requests are left until the server starts to delay the response | | delay | number | undefined | value 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:

| Header | Description | | ----------------------- | ------------------------------------------------------------------------------------------------ | | x-slow-down-limit | how many requests in total the client can make until the server starts to slow down the response | | x-slow-down-remaining | how many requests remain to the client in the timeWindow | | x-slow-down-delay | how much delay (in milliseconds) has been applied to this request |

Configuration

| Name | Type | Default Value | Description | | ---------------------- | ---------------------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | delay | string | number | 1 second | Base 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. | | delayAfter | number | 5 | number of requests received during timeWindow before starting to delay responses. Set to 0 to disable delaying. | | maxDelay | string, number | Infinity | the 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. | | timeWindow | string |, number | 30 seconds | The 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. | | inMemoryCacheSize | number | 5000 | The 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) | | redis | Redis client instance from the ioredis package | undefined | by 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. | | headers | boolean | true | flag to add custom headers x-slow-down-limit, x-slow-down-remaining, x-slow-down-delay for all server responses. | | keyGenerator | function | (req) => req.ip | Function used to generate keys to uniquely identify requests coming from the same user | | onLimitReached | function | undefined | Function that gets called the first time the limit is reached within timeWindow. | | skipFailedRequests | boolean | false | When true, failed requests (status >= 400) won't be counted. | | skipSuccessfulRequests | boolean | false | When true, successful requests (status < 400) won't be counted. | | skip | function | undefined | Function 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.