Skip to content

Commit

Permalink
fix: Correctly retry and handle the redirect in range
Browse files Browse the repository at this point in the history
  • Loading branch information
ci010 committed Jan 3, 2024
1 parent 9d47f43 commit 1565e64
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 11 deletions.
1 change: 1 addition & 0 deletions packages/file-transfer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export * from './agent'
export * from './rangePolicy'
export * from './abort'
export * from './progress'
export * from './retry'
export * from './validator'
export * from './download'
29 changes: 19 additions & 10 deletions packages/file-transfer/range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ export async function * range(
},
})

let nextUrl = url
while (true) {
try {
const { opaque } = await stream(url, {
const { opaque } = await stream(nextUrl, {
method: 'GET',
dispatcher,
headers: {
Expand All @@ -67,21 +68,29 @@ export async function * range(
maxRedirections: 2,
signal: abortSignal,
opaque: { fileStream },
}, ({ opaque, headers, statusCode }) => {
}, ({ opaque, headers: responseHeaders, statusCode }) => {
if (statusCode >= 300) {
(opaque as any).error = Object.assign(new Error(`Unexpected status code ${statusCode} from ${url}`), {
name: 'UnexpectedStatusCodeError',
range: segment.end < 0 ? undefined : `bytes=${segment.start}-${(segment.end) ?? ''}`,
})
// return a run-away writable
return new Writable({ write(chunk, en, cb) { cb() } })
if (typeof responseHeaders.location === 'string') {
nextUrl = new URL(responseHeaders.location)
Object.assign(opaque as any, { continue: true })
} else {
(opaque as any).error = Object.assign(new Error(`Unexpected status code ${statusCode} from ${url}`), {
name: 'UnexpectedStatusCodeError',
range: segment.end < 0 ? undefined : `bytes=${segment.start}-${(segment.end) ?? ''}`,
})
// return a run-away writable
return new Writable({ write(chunk, en, cb) { cb() } })
}
}
if (typeof headers['content-length'] === 'string') {
contentLength = Number.parseInt(headers['content-length'] ?? '0')
if (typeof responseHeaders['content-length'] === 'string') {
contentLength = Number.parseInt(responseHeaders['content-length'] ?? '0')
segment.end = contentLength
}
return (opaque as any).fileStream as Writable
})
if ((opaque as any).continue) {
continue
}
if ((opaque as any).error) {
throw (opaque as any).error
}
Expand Down
9 changes: 8 additions & 1 deletion packages/file-transfer/retry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,22 @@ export function resolveRetryHandler(options?: DefaultRetryPolicyOptions | RetryP
return createDefaultRetryHandler(options?.maxRetryCount ?? 3)
}

const kHandled = Symbol('Handled')
export function createDefaultRetryHandler(maxRetryCount = 3) {
const handler: RetryPolicy = {
async retry(url, attempt, error) {
if (error[kHandled]) {
await setTimeout(error[kHandled])
return true
}
if (attempt < maxRetryCount) {
if (error instanceof errors.HeadersTimeoutError ||
error instanceof errors.BodyTimeoutError ||
error instanceof (errors as any).ConnectTimeoutError ||
error instanceof errors.SocketError) {
await setTimeout(attempt * 1000)
const timeout = (attempt + 1) * 1000
Object.defineProperty(error, kHandled, { value: timeout, enumerable: false })
await setTimeout(timeout)
return true
}
}
Expand Down

0 comments on commit 1565e64

Please sign in to comment.