Files
vercel/test/lib/deployment/fetch-retry.js
JJ Kasper 0da7ea7b78 Add retry handling when hitting SSO (#11061)
This aims to reduce flakiness when SSO disabling for a test project is
still disabling/propagating.

x-ref:
https://github.com/vercel/vercel/actions/runs/7563953104/job/20597320056?pr=11059
x-ref:
https://github.com/vercel/vercel/actions/runs/7563953104/job/20597322078?pr=11059

---------

Co-authored-by: Nathan Rajlich <n@n8.io>
Co-authored-by: Sean Massa <EndangeredMassa@gmail.com>
2024-01-18 13:17:49 -08:00

67 lines
2.2 KiB
JavaScript

const fetch = require('node-fetch');
const retryBailByDefault = require('./retry-bail-by-default.js');
const ABSOLUTE_URL_PATTERN = /^https?:\/\//i;
async function fetchRetry(url, ...rest) {
if (!ABSOLUTE_URL_PATTERN.test(url)) {
throw new Error(`fetch url must be absolute: "${url}"`);
}
return await retryBailByDefault(
async canRetry => {
try {
const requestIds = [];
for (let i = 60; i >= 0; i--) {
const res = await fetch(url, ...rest);
if (res.status === 401) {
const clonedRes = res.clone();
const body = await clonedRes.text();
if (body.includes('https://vercel.com/sso-api')) {
requestIds.push(res.headers.get('x-vercel-id'));
if (i === 0) {
console.error(
`Failed request ids (because of 401s): `,
JSON.stringify(requestIds, null, 2)
);
throw new Error(
`Failed to fetch ${url}, received 401 status for over 1 minute`
);
}
} else {
return res;
}
await new Promise(resolve => setTimeout(resolve, 1000));
} else {
return res;
}
}
} catch (error) {
if (error.type === 'request-timeout') {
// FetchError: network timeout at: ...
throw canRetry(error);
} else if (error.code === 'ENOTFOUND') {
// getaddrinfo ENOTFOUND api.vercel.com like some transient dns issue
throw canRetry(error);
} else if (error.code === 'ETIMEDOUT') {
// request to https://api-gru1.vercel.com/v3/now/deployments/dpl_FBWWhpQomjgwjJLu396snLrGZYCm failed, reason:
// connect ETIMEDOUT 18.228.143.224:443
throw canRetry(error);
} else if (error.code === 'ECONNREFUSED') {
// request to https://test2020-dhdy1xrfa.vercel.app/blog/post-3 failed, reason:
// connect ECONNREFUSED 76.76.21.21:443
throw canRetry(error);
} else if (error.code === 'ECONNRESET') {
throw canRetry(error);
}
throw error;
}
},
{ factor: 2, retries: 3 }
);
}
module.exports = fetchRetry;