mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
chore: respect retry-after header for rate-limiting (#35957)
This commit is contained in:
1 parent
f8b3bfc4d6
commit
4ea088d93d
3 files changed
+22
-4
No files matched your search
@@ -63,10 +63,12 @@ function pgMetaGuard(request: Request) {
|
||||
// If there is no valid `x-connection-encrypted`, pg-meta will necesseraly fail to connect to the target database
|
||||
// in such case, we save the hops and throw a 421 response instead
|
||||
if (!isValidConnString(request.headers.get('x-connection-encrypted'))) {
|
||||
const retryAfterHeader = request.headers.get('Retry-After')
|
||||
throw new ResponseError(
|
||||
'API Error: happened while trying to acquire connection to the database',
|
||||
400,
|
||||
request.headers.get('X-Request-Id') ?? undefined
|
||||
request.headers.get('X-Request-Id') ?? undefined,
|
||||
retryAfterHeader ? parseInt(retryAfterHeader) : undefined
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -98,6 +100,8 @@ client.use(
|
||||
// add code field to body
|
||||
body.code = response.status
|
||||
body.requestId = request.headers.get('X-Request-Id')
|
||||
const retryAfterHeader = response.headers.get('Retry-After')
|
||||
body.retryAfter = retryAfterHeader ? parseInt(retryAfterHeader) : undefined
|
||||
|
||||
return new Response(JSON.stringify(body), {
|
||||
headers: response.headers,
|
||||
@@ -136,9 +140,11 @@ export const handleError = (error: unknown): never => {
|
||||
const errorCode = 'code' in error && typeof error.code === 'number' ? error.code : undefined
|
||||
const requestId =
|
||||
'requestId' in error && typeof error.requestId === 'string' ? error.requestId : undefined
|
||||
const retryAfter =
|
||||
'retryAfter' in error && typeof error.retryAfter === 'number' ? error.retryAfter : undefined
|
||||
|
||||
if (errorMessage) {
|
||||
throw new ResponseError(errorMessage, errorCode, requestId)
|
||||
throw new ResponseError(errorMessage, errorCode, requestId, retryAfter)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ export function getQueryClient() {
|
||||
error instanceof ResponseError &&
|
||||
error.code !== undefined &&
|
||||
error.code >= 400 &&
|
||||
error.code < 500
|
||||
error.code < 500 &&
|
||||
// Still retry on 429s (rate limit)
|
||||
error.code !== 429
|
||||
) {
|
||||
return false
|
||||
}
|
||||
@@ -35,6 +37,14 @@ export function getQueryClient() {
|
||||
|
||||
return false
|
||||
},
|
||||
retryDelay(failureCount, error) {
|
||||
if (error instanceof ResponseError && error.retryAfter) {
|
||||
return error.retryAfter * 1000
|
||||
}
|
||||
|
||||
// react-query default: doubles, starting at 1000ms, with each attempt, but will not exceed 30 seconds
|
||||
return Math.min(1000 * 2 ** failureCount, 30000)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -99,11 +99,13 @@ export type SupaResponse<T> = T | ResponseFailure
|
||||
export class ResponseError extends Error {
|
||||
code?: number
|
||||
requestId?: string
|
||||
retryAfter?: number
|
||||
|
||||
constructor(message: string | undefined, code?: number, requestId?: string) {
|
||||
constructor(message: string | undefined, code?: number, requestId?: string, retryAfter?: number) {
|
||||
super(message || 'API error happened while trying to communicate with the server.')
|
||||
this.code = code
|
||||
this.requestId = requestId
|
||||
this.retryAfter = retryAfter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user