简体   繁体   中英

Concurrent API requests with https module results in sporadic ETIMEDOUT errors

I'm making a bunch of calls, and due to the number of retries I've counted 16981 calls to our third party API. There shouldn't be more than 1000-1500 calls total, so the overwhelming majority of these are probably retries. Very early on I get a 409 back, so my request code retries, which I think causes a cascading problem. After enough calls I hit a ETIMEDOUT error, so I retry again, which is sucking up a ton of execution time.

My ulimit is 4864, so I don't know if that's low enough for it to be the problem.

How can I refactor my code to handle concurrency better and avoid these constant retries? I'm still learning and not sure what a good approach to fix this would be.

Here's my request code:

'use strict';

const https = require('https');
const Url = require('url');
const util = require('util');

function createRequest(requestUrl, body, requestHeaders, type = 'GET') {
    // Creates a post request at url with the given body

    return new Promise((resolve, reject) => {

        const retry = function() {
            // console.log('retrying...');
            createRequest(requestUrl, body, requestHeaders, type);
        }

        const parsedUrl = Url.parse(requestUrl, true, true);
        const options = {
            hostname: parsedUrl.hostname,
            path: parsedUrl.path,
            method: type,
            headers: requestHeaders
        };
        const req = https.request(options, (res) => {
            // console.log("Retry after: ", res.headers.date);
            let responseString = '';

            res.on('data', (dataChunk) => {
                responseString += dataChunk;
            });

            res.on('end', () => {
                if (res.statusCode === 200) {
                    resolve(responseString);
                } else if (res.statusCode === 409) {
                    setTimeout(function() {
                        return resolve(createRequest(requestUrl, body, requestHeaders, type));
                    }, res.headers['retry-after'] * 1000);
                }
            });
        });

        if (type === 'POST') {
            req.write(JSON.stringify(body));
        }

        req.on('error', (error) => {
            if (error.code === 'ETIMEDOUT') {
                //console.log('Encountered ETIMEDOUT. Retrying call...');
                console.log('MError: ', util.inspect(error, { showHidden: true, depth: 2 }));

                setTimeout(function() {
                    return resolve(createRequest(requestUrl, body, requestHeaders, type));
                }, 1000);
            }
            // reject(error);
        });

        req.end();
    });
}

module.exports = {
    createRequest
};

And the error:

MError:  { Error: connect ETIMEDOUT 52.49.220.252:443
at Object.exports._errnoException (util.js:1018:11)
at exports._exceptionWithHostPort (util.js:1041:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1086:14)
  [message]: 'connect ETIMEDOUT 52.49.220.252:443',
  code: 'ETIMEDOUT',
  errno: 'ETIMEDOUT',
  syscall: 'connect',
  address: '52.49.220.252',
  port: 443 }

If it is timing out then you can increase the timeout but https.request() doesn't provide an option for the same. You can use request module for the same and set an upper value of timeout. Try out and let me know.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM