fix(opencode): cap session retries with jitter (#41939)
This commit is contained in:
@@ -25,8 +25,10 @@ export type Retryable = {
|
||||
|
||||
export const RETRY_INITIAL_DELAY = 2000
|
||||
export const RETRY_BACKOFF_FACTOR = 2
|
||||
export const RETRY_JITTER_FACTOR = 0.25
|
||||
export const RETRY_MAX_DELAY_NO_HEADERS = 30_000 // 30 seconds
|
||||
export const RETRY_MAX_DELAY = 2_147_483_647 // max 32-bit signed integer for setTimeout
|
||||
export const RETRY_MAX_RETRIES = 5
|
||||
|
||||
const RETRYABLE_MESSAGE_PATTERNS = [
|
||||
/429|500|502|503|504|524/i,
|
||||
@@ -41,7 +43,7 @@ function cap(ms: number) {
|
||||
return Math.min(ms, RETRY_MAX_DELAY)
|
||||
}
|
||||
|
||||
export function delay(attempt: number, error?: SessionV1.APIError) {
|
||||
export function delay(attempt: number, error?: SessionV1.APIError, random = Math.random()) {
|
||||
if (error) {
|
||||
const headers = error.data.responseHeaders
|
||||
if (headers) {
|
||||
@@ -67,11 +69,16 @@ export function delay(attempt: number, error?: SessionV1.APIError) {
|
||||
}
|
||||
}
|
||||
|
||||
return cap(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1))
|
||||
return cap(exponential(attempt, random))
|
||||
}
|
||||
}
|
||||
|
||||
return cap(Math.min(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1), RETRY_MAX_DELAY_NO_HEADERS))
|
||||
return cap(Math.min(exponential(attempt, random), RETRY_MAX_DELAY_NO_HEADERS))
|
||||
}
|
||||
|
||||
function exponential(attempt: number, random: number) {
|
||||
const base = RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1)
|
||||
return Math.ceil(base + base * RETRY_JITTER_FACTOR * random)
|
||||
}
|
||||
|
||||
export function retryable(error: Err, provider: string) {
|
||||
@@ -182,6 +189,7 @@ export function policy(opts: {
|
||||
const error = opts.parse(meta.input)
|
||||
const retry = retryable(error, opts.provider)
|
||||
if (!retry) return Cause.done(meta.attempt)
|
||||
if (meta.attempt > RETRY_MAX_RETRIES) return Cause.done(meta.attempt)
|
||||
return Effect.gen(function* () {
|
||||
const wait = delay(meta.attempt, SessionV1.APIError.isInstance(error) ? error : undefined)
|
||||
const now = yield* Clock.currentTimeMillis
|
||||
|
||||
Reference in New Issue
Block a user