fix: avoid storage probe redirect timeouts

This commit is contained in:
FengLee
2026-05-20 15:42:28 +08:00
parent 4320a1499c
commit 2137a4b23f
2 changed files with 46 additions and 2 deletions

View File

@@ -18,14 +18,33 @@ export function getMigrationStorageUrlConcurrency(env = process.env) {
export async function checkStorageUrl(baseUrl, storageUrl, options = {}) {
const timeoutMs = Number(options.timeoutMs || 10_000);
const fetchImpl = options.fetchImpl || fetch;
const targetUrl = `${baseUrl}${storageUrl}`;
try {
const response = await fetchImpl(`${baseUrl}${storageUrl}`, {
const response = await fetchImpl(targetUrl, {
method: 'HEAD',
redirect: 'manual',
signal: AbortSignal.timeout(timeoutMs),
});
await response.body?.cancel?.();
if (!response.ok) {
if (isReachableStorageResponse(response)) {
return { ok: true };
}
if (response.status !== 405) {
return { ok: false, error: `HTTP ${response.status}` };
}
const fallback = await fetchImpl(targetUrl, {
redirect: 'manual',
signal: AbortSignal.timeout(timeoutMs),
});
await fallback.body?.cancel?.();
if (!isReachableStorageResponse(fallback)) {
return { ok: false, error: `HTTP ${fallback.status}` };
}
return { ok: true };
} catch (error) {
return {
@@ -34,3 +53,10 @@ export async function checkStorageUrl(baseUrl, storageUrl, options = {}) {
};
}
}
function isReachableStorageResponse(response) {
if (response.ok) return true;
return response.status >= 300
&& response.status < 400
&& Boolean(response.headers?.get?.('location'));
}

View File

@@ -71,6 +71,24 @@ await runTest('migration storage URL check records fetch failures instead of thr
});
});
await runTest('migration storage URL check treats local-storage redirects as reachable', async () => {
const calls = [];
const result = await checkStorageUrl('http://127.0.0.1:8000', '/api/local-storage/gallery/images/work.png', {
timeoutMs: 10,
fetchImpl: async (_url, init) => {
calls.push(init);
return new Response(null, {
status: 302,
headers: { Location: 'https://object-storage.example/work.png' },
});
},
});
assert.deepEqual(result, { ok: true });
assert.equal(calls[0].method, 'HEAD');
assert.equal(calls[0].redirect, 'manual');
});
await runTest('migration integrity script uses resilient storage URL helpers', () => {
const source = read('scripts/migration-integrity-check.mjs');