使用 https 模块的并发 API 请求会导致偶发的 ETIMEDOUT 错误



我正在做一堆调用,由于重试次数,我已经计算了16981次对第三方API的调用。总共不应超过 1000-1500 个调用,因此其中绝大多数可能是重试。很早的时候我得到了一个 409,所以我的请求代码重试,我认为这会导致级联问题。在足够多的调用之后,我遇到了 ETIMEDOUT 错误,所以我再次重试,这占用了大量的执行时间。

我的 ulimit 是 4864,所以我不知道这是否低到足以成为问题所在。

如何重构代码以更好地处理并发并避免这些不断重试?我仍在学习,不确定解决此问题的好方法是什么。

这是我的请求代码:

'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
};

和错误:

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 }

如果超时,则可以增加超时,但https.request()不提供相同的选项。您可以使用请求模块进行相同的操作,并设置超时的上限值。尝试一下,让我知道。

最新更新