Skip to content

Commit

Permalink
feat: support for handling of socket hangup
Browse files Browse the repository at this point in the history
Tries to solve the problem reported in node-fetch/node-fetch#1735.
This can be considered a persistent issue that is only minimized by this solution.
  • Loading branch information
joamag committed Oct 25, 2023
1 parent 2f9eb91 commit 5c148fd
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 4 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

*
* Made changes to the way connections are handled so that connections that are kept-alive are do not generate ECONNRESET - related to [node-fetch/node-fetch#1735](https://github.com/node-fetch/node-fetch/issues/1735)

### Fixed

Expand Down
55 changes: 52 additions & 3 deletions js/api/api.js
Expand Up @@ -76,7 +76,7 @@ export class API extends Observable {

async _methodBasic(method, url, options = {}) {
const params = options.params !== undefined ? options.params : {};
const headers = options.headers !== undefined ? options.headers : {};
let headers = options.headers !== undefined ? options.headers : {};
const kwargs = options.kwargs !== undefined ? options.kwargs : {};
const handle = options.handle !== undefined ? options.handle : true;
const getAgent = options.getAgent !== undefined ? options.getAgent : undefined;
Expand All @@ -87,7 +87,22 @@ export class API extends Observable {
});
const query = urlEncode(params || {});
if (query) url += url.includes("?") ? "&" + query : "?" + query;
const response = await fetch(url, {

// runs a dummy agent retrieval to check if the current agent
// is set to keep connections alive
const _getAgent = getAgent || globals.getAgent || undefined;
const agent = _getAgent ? _getAgent(new URL(url)) : undefined;
const keepAlive = (agent && agent.keepAlive) || false;

headers = Object.assign({}, headers);
if (keepAlive) headers.Connection = "keep-alive";

// adds a new forced loop, tick to the event loop, this should
// help solve closed connection handling problems in node-fetch
// while not adding extra issues
await new Promise(resolve => setTimeout(resolve, 0));

const response = await fetchRetry(url, {
method: method,
headers: headers || {},
agent: getAgent || globals.getAgent || undefined
Expand Down Expand Up @@ -133,10 +148,22 @@ export class API extends Observable {
mime = mime || "application/x-www-form-urlencoded";
}

// runs a dummy agent retrieval to check if the current agent
// is set to keep connections alive
const _getAgent = getAgent || globals.getAgent || undefined;
const agent = _getAgent ? _getAgent(new URL(url)) : undefined;
const keepAlive = (agent && agent.keepAlive) || false;

headers = Object.assign({}, headers);
if (mime) headers["Content-Type"] = mime;
if (keepAlive) headers.Connection = "keep-alive";

const response = await fetch(url, {
// adds a new forced loop, tick to the event loop, this should
// help solve closed connection handling problems in node-fetch
// while not adding extra issues
await new Promise(resolve => setTimeout(resolve, 0));

const response = await fetchRetry(url, {
method: method,
headers: headers || {},
body: data,
Expand Down Expand Up @@ -255,6 +282,28 @@ export class API extends Observable {
}
}

export const fetchRetry = async (url, options = {}, retries = 5, delay = 0, timeout = 100) => {
let response = null;
while (!response && retries > 0) {
const start = Date.now();
try {
response = await fetch(url, options);
} catch (error) {
const isHangup =
error.name === "FetchError" &&
error.code === "ECONNRESET" &&
error.message.includes("socket hang up");
const elapsed = Date.now() - start;
if (retries === 0 || elapsed > timeout || !isHangup) {
throw error;
}
await new Promise(resolve => setTimeout(resolve, delay));
retries--;
}
}
return response;
};

export const buildGetAgent = (AgentHttp, AgentHttps, set = true, options = {}) => {
const httpAgent = new AgentHttp({
keepAlive: options.keepAlive === undefined ? true : options.keepAlive,
Expand Down

0 comments on commit 5c148fd

Please sign in to comment.