@jspm/generator
Version:
Package Import Map Generation Tool
75 lines (73 loc) • 2.33 kB
JavaScript
let retryCount = 5, poolSize = 100;
function setRetryCount(count) {
retryCount = count;
}
/**
* Wraps a fetch request with pooling, and retry logic on exceptions (emfile / network errors).
*/ function wrappedFetch(fetch) {
const wrappedFetch = async function(url, ...args) {
url = url.toString();
let retries = 0;
try {
await pushFetchPool();
while(true){
try {
return await fetch(url, ...args);
} catch (e) {
if (retries++ >= retryCount) throw e;
}
}
} finally{
popFetchPool();
}
};
wrappedFetch.arrayBuffer = async function(url, ...args) {
url = url.toString();
let retries = 0;
try {
await pushFetchPool();
while(true){
try {
var res = await fetch(url, ...args);
} catch (e) {
if (retries++ >= retryCount) throw e;
continue;
}
switch(res.status){
case 200:
case 304:
break;
// not found = null
case 404:
return null;
default:
throw new Error(`Invalid status code ${res.status}`);
}
try {
return await res.arrayBuffer();
} catch (e) {
if (retries++ >= retryCount && e.code === "ERR_SOCKET_TIMEOUT" || e.code === "ETIMEOUT" || e.code === "ECONNRESET" || e.code === "FETCH_ERROR") {}
}
}
} finally{
popFetchPool();
}
};
wrappedFetch.text = async function(url, ...args) {
const arrayBuffer = await this.arrayBuffer(url, ...args);
if (!arrayBuffer) return null;
return new TextDecoder().decode(arrayBuffer);
};
return wrappedFetch;
}
// restrict in-flight fetches to a pool of 100
let p = [];
let c = 0;
function pushFetchPool() {
if (++c > poolSize) return new Promise((r)=>p.push(r));
}
function popFetchPool() {
c--;
if (p.length) p.shift()();
}
export { setRetryCount as s, wrappedFetch as w };