Search code examples
javascriptthrottling

How to check what the throttling limit is for your access to an endpoint with JS


[![enter image description here][1]][1]I need to implement code to check what my throttling limit is on an endpoint (I know it's x times per minute). I've only been able to find an example of this in python, which I have never used. It seems like my options are to run a script to send the request repeatedly until it throttles me or, if possible, query the API to see what the limit is.

Does anyone have a good idea on how to go about this?

Thanks.

Note: The blank space is just data from the api calls. [1]: https://i.sstatic.net/gAFQQ.png


Solution

  • This starts concurrency number of workers (I'm using workers as a loose term here; don't @ me). Each one makes as many requests as possible until one of the requests is rate-limited or it runs out of time. It them reports how many of the requests completed successfully inside the given time window.

    If you know the rate-limit window (1 minute based on your question), this will find the rate-limit. If you need to discover the window, you would want to intentionally exhaust the limit, then slow down the requests and measure the time until they started going through again. The provided code does not do this.

    // call apiCall() a bunch of times, stopping when a apiCall() resolves
    // false or when "until" time is reached, whichever comes first. For example
    // if your limit is 50 req/min (and you give "until" enough time to
    // actually complete 50+ requests) this will call apiCall() 50 times. Each
    // call should return a promise resolving to TRUE, so it will be counted as
    // a success. On the 51st call you will presumably hit the limit, the API
    // will return an error, apiCall() will detect that, and resolve to false.
    // This will cause the worker to stop making requests and return 50.
    async function workerThread(apiCall, until) {
        let successfullRequests = 0;
        while(true) {
            const success = await apiCall();
            // only count it if the request was successful
            // AND finished within the timeframe
            if(success && Date.now() < until) {
                successfullRequests++;
            } else {
                break;
            }
        }
        return successfullRequests;
    }
    
    // this just runs a bunch of workerThreads in parallel, since by doing a
    // single request at a time, you might not be able to hit the limit
    // depending on how slow the API is to return. It returns the sum of each
    // workerThread(), AKA the total number of apiCall()s that resolved to TRUE
    // across all threads.
    async function testLimit(apiCall, concurrency, time) {
        const endTime = Date.now() + time;
        
        // launch "concurrency" number of requests
        const workers = [];
        while(workers.length < concurrency) {
            workers.push(workerThread(apiCall, endTime));
        }
        
        // sum the number of requests that succeeded from each worker.
        // this implicitly waits for them to finish.
        let total = 0;
        for(const worker of workers) {
            total += await worker;
        }
        return total;
    }
    
    // put in your own code to make a trial API call.
    // return true for success or false if you were throttled.
    async function yourAPICall() {
        try {
            // this is a really sloppy example API
            // the limit is ROUGHLY 5/min, but because of the sloppy server-side
            // implementation you might get 4-6.
            const resp = await fetch("https://9072997.com/demos/rate-limit/");
            return resp.ok;
        } catch {
            return false;
        }
    }
    
    // this is a demo of how to use the function
    (async function() {
        // run 2 requests at a time for 5 seconds
        const limit = await testLimit(yourAPICall, 2, 5*1000);
        console.log("limit is " + limit + " requests in 5 seconds");
    })();
    

    Note that this method measures the quota available to itself. If other clients or previous requests have already depleted the quota, it will affect the result.