throttled-fetch
v1.1.1
Published
   
We use this probability to then either reject the request right away or let it through. As this is a rejection probability, it does not work like a conventional circuit-breaker that cuts off the flow of requests, but it lets a few random requests through from time to time to get the updated health status of the called service. So when the backend starts to cope with the load (either due to auto-scaling or any other methods) the rejection probability will start going down and the client slowly returns to normal functioning.
Install
npm i throttled-fetch -Sor
yarn add throttled-fetchUsage
Defaut usage
- Import the library
import throttledFetch from 'throttled-fetch';
// or
const throttledFetch = require('throttled-fetch');- Setup throttler params (if you don't want the defaults)
const customFetch = throttledFetch(); // will use defaults shown below
// OR - You can pass three *optional* params to setup how aggressive your throttling will be
const customFetch = throttledFetch({
K: 2,
// Multiplier that determines aggressiveness of throttling
// Higher value is less agressive, 2 is recommended (default)
windowLength: 120,
// Determines how many seconds wide the requestWindow is.
// default is 120 seconds i.e rejection probability is based on how well the backend has been performing in the last 2 minutes
cleanupFrequency: 60,
// Determines how often requests history is cleaned (delete old keys), default 60 seconds
});- Use your custom throttled-fetch function just like native fetch (with more custom options). More info on how
cross-fetchworks can be found here
// With promises
customFetch('https://example.come', { method: 'get' })
.then(res => res.json())
.catch(err => console.error(err));
// With async/await
const response = await customFetch('https://example.come', { method: 'get' });Usage with your own fetch library
- Import the throttler
import { throttler } from 'throttled-fetch';
// or
const { throttler } = require('throttled-fetch');- Setup throttler params.
const requestThrottler = throttler(); // will use defaults shown below
// OR - You can pass three *optional* params to setup how aggressive your throttling will be
const requestThrottler = throttler({
K: 2,
// Multiplier that determines aggressiveness of throttling
// Higher value is less agressive, 2 is recommended (default)
windowLength: 120,
// Determines how many seconds wide the requestWindow is.
// default is 120 seconds i.e rejection probability is based on how well the backend has been performing in the last 2 minutes
cleanupFrequency: 60,
// Determines how often requests history is cleaned (delete old keys), default 60 seconds
});- Use the return vales
shouldThrottleand the updater to let the throttler know what the response was.
const [shouldThrottle, callOnComplete] = requestThrottler(
'http://example.com/api'
);
if (shouldThrottle) {
callOnComplete(false);
// Reject the request
}
// Handle normal fetch
axios
.get(url)
.then(res => {
res.status < 500
? callOnComplete(true) // if successful request
: callOnComplete(false); // if failed request
// handle success
})
.catch(err => {
callOnComplete(false); // failed request
// handle failure
});Additional options
You can also pass a few boolean options to treat individual endpoints/services differently in terms of throttling if you want
applyThrottling- (default: true) - If you'd like to skip throttling a service/endpoint for some reason (non-critical/external service)removeQueryParams- (default: true) - As this library is aiming to throttle requests based on healthiness of a endpoint/service, it's a good idea to clean out the query params from a url before adding them to the history to keep the history map small and manageable. But if you want to leave them in, essentially meaning you thinkhttp://example.com?foo=bar's bad health should not affect rejection rate ofhttp://example.com?baz=too, you can use this.throttle400s- (default: false) - Services usually return 500s when they are overwhelmed so that is the default definition of failure here, but if you want to include 400s as well (if maybe you want to throttle users who are getting unauthorized response way too much), use this.
Do you need this?
Does your service deal with unexpected traffic surges that your backend sometimes can't cope with? ✅
Are you not sure? It's good to have it anyway ✅
In all other cases, you probably don't need it.
Credits
All the credit for the idea for client-side adaptive throttling goes to Google's SRE team and the authors of the 'Handling Overload' chapter, Alejandro Forero Cuervo and Sarah Chavis.
License
throttled-fetch is licensed under the MIT license © Abhishek Shetty
