Code Monkey home page Code Monkey logo

axios-rate-limit's People

Contributors

acao avatar aishek avatar antonisprovidakis avatar dependabot[bot] avatar frobthebuilder avatar jomel avatar mcuppi avatar megapixel99 avatar mikevinmike avatar terotil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

axios-rate-limit's Issues

Persisting the queued requests

I am thinking maybe you can persist the queued requests using Redis. This is a feature that I needed several times and is not supported via an easy solution like yours. The alternative is to use some sophisticated scheduling package, and it's always a hassle just to do some simple rate-limiting.

I can help with this feature, but I want to know what the maintaining team thinks about it.

maxRequests only the first loop?

Axios makes 2 requests in parallel, but after 30 seconds, it only makes one request at a time instead of two.

const axiosWithRateLimit = rateLimit(axios_update.create(), { maxRequests: 2, perMilliseconds: 30000 })

Slows down on error

This is how load the module:

const axios = require('axios').default;
const rateLimit = require('axios-rate-limit');
http = rateLimit(axios.create(), { maxRPS: 10 })

This is how I'm populating my requests queue:

http.get('https://postman-echo.com/notexistingpage?)
	.then(function (response) {
		console.log('status: '+response.status);
	})
	.catch(function (error) {
		console.log('Error');
	})
	.then(function () {
	});

Each request is getting an error (because of notexistingpage in the url). After the first 10 sent request 1 request per second is sent. If I change notexistingpage in the url with an existing one, requests are sent at 10/sec.
Why is it slowing down to 1 req/sec on error? Using http.getMaxRPS() I get the correct value (10)

Thank you!

Don't count cancelled requests into rate limit if they haven't been executed yet

First, I find this a great library.
My use-case is that I display a large table and for each row, there are 2 requests I need to make. The table uses pagination.
When I go to the next page I cancel all the unfinished requests from the previous page. The old requests don't need to be resolved since they are not going to be displayed, anyway.

I can clearly see that when I jump through the pages in the paginated table, the requests are getting delayed. The old (canceled) requests are getting executed in a "rate-limited" manner. They don't make it to the server but still, they are counted into rate limit. Once the old requests are all done, the new requests are resolved.
I think that this is not a correct behavior and canceled requests should be removed from the rate limiter, thus allowing the new requests getting executed faster.

Do you think that this has the potential to make the implementation of this library more robust?

Ratelimiter does not keep process running until all requests are finished

Problem example

Here it shows a Promise.all does not longer keep the process alive, it terminates... I guess this ratelimiter was implemented with daemonized scripts in mind?

const axios = require('axios')
const rl = require('axios-rate-limit');

// sets max 2 requests per 1 second, other will be delayed
const http = rl(axios.create(), { maxRequests: 2, perMilliseconds: 1000 });

Promise.all([
  http.get('http://httpbin.org/get').then(x => {console.log(1); return x}),
  http.get('http://httpbin.org/get').then(x => {console.log(2); return x}),
  http.get('http://httpbin.org/get').then(x => {console.log(3); return x}),
]).then(x => {
  console.log('after')
})

Problem workaround

If you count yourself how many requests you scheduled and if they are all finished or just add a global timeout to keep the process alive it works:

const axios = require('axios')
const rl = require('axios-rate-limit');

// sets max 2 requests per 1 second, other will be delayed
const http = rl(axios.create(), { maxRequests: 2, perMilliseconds: 1000 });

Promise.all([
  http.get('http://httpbin.org/get').then(x => {console.log(1); return x}),
  http.get('http://httpbin.org/get').then(x => {console.log(2); return x}),
  http.get('http://httpbin.org/get').then(x => {console.log(3); return x}),
]).then(x => {
  console.log('after')
})

setTimeout(function() {
  console.log('kept alive for 5s')
}, 5000)

Priority Queue?

Would it be possible to add a priority queue feature to the library? I.e. if there are 100 queued requests, could you push 10 requests to the front of the queue?

Rate limiter is consuming all errors thrown by axios

The rate limiter intercepts requests and responses from axios and doesn't re-throw errors. This causes any errors thrown by axios to be consumed (i.e., you cannot catch them later on in a try catch block).

This can be fixed by simply adding error handling to the interceptors:

AxiosRateLimit.prototype.enable = function (axios) {
  this.interceptors.request = axios.interceptors.request.use(
    this.requestHandler,
    function (error) {
      return Promise.reject(error)
    }
  )
  this.interceptors.response = axios.interceptors.response.use(
    this.responseHandler,
    function (error) {
      return Promise.reject(error)
    }
  )
}

I've submitted a pull request that addresses this issue: #2

[Feature Request] Better TypeScript suppport

Dear Alexandr

Thank you for implementing a rate-limiting feature for Axios. It works very well!
If you find some time, maybe you could address some TypeScript-related issues I am facing:

  • Export the RateLimitedAxiosInstance interface, so that we can have a specific type (instead of any) in our projects

  • default export axiosRateLimit (instead of export = axiosRateLimit;). I had to turn on a compiler option (esModuleInterop) to make axios-rate-limit work in modern es6 projects.

Thank you!

EDIT:
I've just seen this pull request: #19.

It seems like my second suggestion has already been fixed in 1.2.1. However, I still get that problem. What is the correct import statement in TypeScript now?

Internal setTimeout causes the application to run until the perMilliseconds time is up

If you run this:

const http = rateLimit(axios.create(), { maxRequests: 4, perMilliseconds: 20000 })
http.get('http://localhost:4567/__sinatra__/404.png') 
http.get('http://localhost:4567/__sinatra__/404.png') 
http.get('http://localhost:4567/__sinatra__/404.png') 

It will perform the three requests, and then the application will continue running for 20 seconds until the internal timeout is up.

Multiple limits on the same instance (max per min and max per sec)

I am working with several APIs on my app and a few of them have limits that are not just simply per sec.
For example one of my apis has the following limits:

  • Max 100 requests per 2 minutes
  • Max 20 requests per 1 second

So I have tried implementing it the following way:

axiosRateLimit(baseAxios.create(), {
  maxRequests: 1, // 1
  perMilliseconds: 1200 // per 1.2 seconds
  // 100 requests per 2 minutes, 50 requests per 60 seconds, 60 seconds / 50 requests = 1 per 1.2 seconds
});

But it can't take advantage of the 20 requests per 1 second limit, because to adhere to the 100 requests per 2 minutes, I have to limit it to 1 per 1.2 seconds, otherwise if I limit it to 20 per second, I can do 2400 requests in 2 minutes.

So how can I implement both conditions and have them both working together?
What if I need to do only 50 requests every 2 minutes, with the current implementation, it will take me 1 minute for all of them, and I am not taking advantage of the 20 per second (becaus if I do, I can do it in 3 seconds, instead of 1 minute).

Is there a way to accomplish this with this library? Initially I thought that the maxRequests works with perMilliseconds and maxRPS can be used to handle the other case, so when all 3 are supplied I thought it would be like:

{
  maxRequests: 100, // 100 max requests
  perMilliseconds: 2 * 60 * 1000, // per 2 minutes
  maxRPS: 20 // 20 max per second
}

But the docs say:

// sets max 2 requests per 1 second, other will be delayed
// note maxRPS is a shorthand for perMilliseconds: 1000, and it takes precedence
// if specified both with maxRequests and perMilliseconds
const http = rateLimit(axios.create(), { maxRequests: 2, perMilliseconds: 1000, maxRPS: 2 })

So obviously it doesnt work the way I expected it to work, is there a way to achieve what I want?

Enable Sharing the AxiosRateLimit instance between AxiosClient instances

Currently the axiosRateLimit function is the only export from the module, but I would like to be able to share rate-limiting between axios clients. That is, I'd like to be able to do something like this:

import axios from 'axios';
import rateLimit, { AxiosRateLimiter } from 'axios-rate-limit'

const limiter = AxiosRateLimiter( { maxRequests: 2, perMilliseconds: 1000, maxRPS: 2 } );

const sheet1 = rateLimit(axios.create({ baseURL: `${SHEETS_API_BASE_URL}/${spreadsheetId1}` }), { rateLimiter: limiter});
const sheet2 = rateLimit(axios.create({ baseURL: `${SHEETS_API_BASE_URL}/${spreadsheetId2}` }), { rateLimiter: limiter}); 

So that both sheet1 and sheet2 are rate-limited as if they were a single rate limited axios client. I.e. if two requests are done in the same second on client1, then a third request in the same second for client2 would be rate-limited into the next second.

From what I can see in the code, it's almost ready for that, as the axios parameter in the constructor for AxiosRateLimit is only used for the .enable() call, and in there it's only used to .use() the interceptors. And though it stores the return values of the .use() calls, it doesn't actually do anything with them.

For node.js add module.exports

So, the below code block doesn't work for nodejs apps, may be you targeted the frontend env.

exports.__esModule = true
exports.name = 'axiosRateLimit'
exports.default = axiosRateLimit

Adding one more line for the nodejs type will do the job:

module.exports = axiosRateLimit

typescript typings issues

hey thanks for this great module!

quick note - the options for instantiating the module all show as required options, and also maxRPS is not present in the available options

so, for example, this fails with typescript:

const http = rateLimit(axios.create(), {
  maxRPS: parseInt(process.env.ENV_VARIABLE, 10) || 50,
})

because:

  1. maxRPS is not an available option according to the typings
  2. required values of maxRequests and perMilliseconds are not present

Change RPS on the fly

Hey,

is it possible to change the maxRPS on the fly?

I'm trying to:

  • Launch 10,000 requests
  • When one of the response returns response.data.length === 0 (response is empty) I want to cancel all other requests (using axios CancelToken)
  • I use client.setMaxRPS(100000) before calling cancelToken.cancel()
  • But canceling still uses rate limit

Is it possible to change the RPS so the tokens get canceled faster / immediately?

Or do you guys suggest some simpler solution?

Thanks!

Orchestration with axios-cache-adapter

Thanks first for creating this tools, it was perfect for our use case!

We are using it in conjunction with https://github.com/RasCarlito/axios-cache-adapter, which allows us to cache some requests to speed up the process and reduce network trips.

The problem we have is that the cache requests count for the limit as well, is there a way to maybe expose a hook or similar to prevent a request counting for the limit if it was served from the cache? I can send a PR once we come up with the best solution.

Issue with the latest axios (v.1)

This library has used the axios: ^0.18.0 as a devDependency to pull in the Axios while development.

  • It has to be in the dependency section of the package.json to force relevant Axios version constraint as well.
{
   "dependencies": {
      "axios": "^0.18.0",
   }
}

This way your package will not be installed in the projects using axios: 1.13.0.

I used your library to solve the rate limiting Issue in our project, But wasted an entire day as I relied on TS to tell me there wasn't any Error. Found out the Issue doing debugging the runtime values.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.