@@ -42,6 +42,11 @@ export type NpmViewFields = {
|
42 | 42 | tarball?: string; |
43 | 43 | }; |
44 | 44 | |
| 45 | +type FetchWithRetryResult = { |
| 46 | +response: Response; |
| 47 | +signal: AbortSignal; |
| 48 | +}; |
| 49 | + |
45 | 50 | type WorkflowRunSummary = { |
46 | 51 | id: string; |
47 | 52 | label: string; |
@@ -262,16 +267,17 @@ async function fetchWithRetry(
|
262 | 267 | url: string, |
263 | 268 | options: RequestInit, |
264 | 269 | attempts: number, |
265 | | -): Promise<Response> { |
| 270 | +): Promise<FetchWithRetryResult> { |
266 | 271 | let lastError: unknown; |
267 | 272 | for (let attempt = 1; attempt <= attempts; attempt += 1) { |
268 | 273 | try { |
| 274 | +const signal = AbortSignal.timeout(CLAWHUB_REQUEST_TIMEOUT_MS); |
269 | 275 | const response = await fetch(url, { |
270 | 276 | ...options, |
271 | | -signal: AbortSignal.timeout(CLAWHUB_REQUEST_TIMEOUT_MS), |
| 277 | + signal, |
272 | 278 | }); |
273 | 279 | if (response.status !== 429 && response.status < 500) { |
274 | | -return response; |
| 280 | +return { response, signal }; |
275 | 281 | } |
276 | 282 | lastError = new Error(`HTTP ${response.status}`); |
277 | 283 | } catch (error) { |
@@ -288,23 +294,28 @@ async function fetchWithRetry(
|
288 | 294 | } |
289 | 295 | |
290 | 296 | async function fetchJsonWithRetry(url: string): Promise<unknown> { |
291 | | -const response = await fetchWithRetry(url, { headers: { accept: "application/json" } }, 5); |
| 297 | +const { response, signal } = await fetchWithRetry( |
| 298 | +url, |
| 299 | +{ headers: { accept: "application/json" } }, |
| 300 | +5, |
| 301 | +); |
292 | 302 | if (!response.ok) { |
293 | 303 | throw new Error(`${url} returned HTTP ${response.status}.`); |
294 | 304 | } |
295 | | -return await readBoundedJsonResponse(response, url); |
| 305 | +return await readBoundedJsonResponse(response, url, undefined, { signal }); |
296 | 306 | } |
297 | 307 | |
298 | 308 | export async function readBoundedJsonResponse( |
299 | 309 | response: Response, |
300 | 310 | label: string, |
301 | 311 | maxBytes = CLAWHUB_RESPONSE_BODY_MAX_BYTES, |
| 312 | +options: { signal?: AbortSignal } = {}, |
302 | 313 | ): Promise<unknown> { |
303 | | -return parseJson(await readBoundedResponseText(response, label, maxBytes), label); |
| 314 | +return parseJson(await readBoundedResponseText(response, label, maxBytes, options), label); |
304 | 315 | } |
305 | 316 | |
306 | 317 | async function fetchStatusWithRetry(url: string, method: "GET" | "HEAD"): Promise<number> { |
307 | | -const response = await fetchWithRetry(url, { method, redirect: "manual" }, 5); |
| 318 | +const { response } = await fetchWithRetry(url, { method, redirect: "manual" }, 5); |
308 | 319 | return response.status; |
309 | 320 | } |
310 | 321 | |
|