Skip to content
REST API

如何用 supabase-js 做自动重试

Learn how to configure automatic retries for your Supabase API requests.

PostgREST 查询的内置重试 #

🌐 Built-in retries for PostgREST queries

从 supabase-js v2.102.0 开始,PostgREST 查询(.from()、.rpc())包含了对临时错误的内置自动重试。重试 默认启用,并使用指数退避。

🌐 Starting with supabase-js v2.102.0, PostgREST queries (.from(), .rpc()) include built-in automatic retries for transient errors. Retries are enabled by default and use exponential backoff.

supabase-js 只会重试幂等的 HTTP 方法:GET、HEAD 和 OPTIONS。内置的重试策略不会重试 POST、PATCH、PUT 或 DELETE。对于它会重试的方法,它会在 HTTP 状态码为 503 服务不可用和 520 未知错误时重试,也会在网络失败时重试。

因为 .rpc() 默认发送 POST,所以 RPC 调用不会重试。传入 { get: true } 或 { head: true } 可以把调用改为 GET 或 HEAD,这样内置的重试机制就会起作用。

🌐 Because .rpc() sends POST by default, RPC calls aren't retried. Pass { get: true } or { head: true } to send the call as GET or HEAD, which the built-in retries cover.

设置请求超时 #

🌐 Set a request timeout

重试只会在请求失败后才运行。一直挂起的请求永远不会失败,所以它永远不会触发重试逻辑。这种情况可能发生在上游响应慢导致超时时。传递一个 AbortSignal 来限制请求可以耗费的时间:

🌐 Retries only run after a request fails. A request that hangs never fails, so it never reaches the retry logic. This can happen during a slow upstream timeout. Pass an AbortSignal to cap how long a request can take:

const { data, error } = await supabase
.from('your_table')
.select('*')
.abortSignal(AbortSignal.timeout(10_000))

禁用内置重试 #

🌐 Disable built-in retries

如果你更喜欢自己处理重试,可以禁用内置的重试功能:

🌐 If you prefer to handle retries yourself, you can disable the built-in retry behavior:

import { } from '@supabase/supabase-js'
const = ('https://your-project-id.supabase.co', 'your-publishable-key', {
: {
: false,
},
})

使用 fetch-retry#

🌐 Custom retries with fetch-retry

如果你想对重试行为有更多控制,或者想给非 PostgREST 请求(如认证、存储、函数)添加重试,你可以使用 fetch-retry 包。这个方法会封装原生的 fetch 函数,并适用于客户端发出的所有请求。

🌐 For more control over retry behavior, or to add retries to non-PostgREST requests (auth, storage, functions), you can use the fetch-retry package. This approach wraps the native fetch function and applies to all requests made by the client.

1. 安装依赖 #

🌐 1. Install dependencies

要开始,确保你的项目里已经安装了 supabase-js 和 fetch-retry:

🌐 To get started, ensure you have both supabase-js and fetch-retry installed in your project:

npm install @supabase/supabase-js fetch-retry

2. 封装 fetch 函数 #

🌐 2. Wrap the fetch function

fetch-retry 包通过封装原生的 fetch 函数来工作。你可以创建一个带有重试逻辑的自定义 fetch 实例,然后传给 supabase-js 客户端。

🌐 The fetch-retry package works by wrapping the native fetch function. You can create a custom fetch instance with retry logic and pass it to the supabase-js client.

import { createClient } from '@supabase/supabase-js'
import fetchRetry from 'fetch-retry'
// Wrap the global fetch with fetch-retry
const fetchWithRetry = fetchRetry(fetch)
// Create a Supabase client instance with the custom fetch
const supabase = createClient('https://your-project-id.supabase.co', 'sb_publishable_...', {
global: {
fetch: fetchWithRetry,
},
})

3. 配置重试选项 #

🌐 3. Configure retry options

你可以配置 fetch-retry 选项来控制重试行为,比如重试次数、重试延迟以及哪些错误会触发重试。

🌐 You can configure fetch-retry options to control retry behavior, such as the number of retries, retry delay, and which errors should trigger a retry.

这是一个带有自定义重试选项的示例:

🌐 Here is an example with custom retry options:

const fetchWithRetry = fetchRetry(fetch, {
retries: 3, // Number of retry attempts
retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000), // Exponential backoff
retryOn: [520], // Retry only on Cloudflare errors
})

在这个例子中,retryDelay 函数实现了指数退避策略,并且仅在特定的 HTTP 状态码下才会触发重试。

🌐 In this example, the retryDelay function implements an exponential backoff strategy, and retries are triggered only for specific HTTP status codes.

4. 使用 Supabase 客户端 #

🌐 4. Using the Supabase client

集成了 fetch-retry 后,你可以像平常一样使用 Supabase 客户端。重试逻辑会自动应用到 supabase-js 发出的所有网络请求。

🌐 With fetch-retry integrated, you can use the Supabase client as usual. The retry logic will automatically apply to all network requests made by supabase-js.

async function fetchData() {
const { data, error } = await supabase.from('your_table').select('*')
if (error) {
console.error('Error fetching data:', error)
} else {
console.log('Fetched data:', data)
}
}
fetchData()

5. 针对特定请求微调重试次数 #

🌐 5. Fine-tuning retries for specific requests

如果你需要针对某些请求使用不同的重试逻辑,你可以使用 retryOn 配合自定义函数来检查 URL 或响应,然后决定是否重试请求。

🌐 If you need different retry logic for certain requests, you can use the retryOn with a custom function to inspect the URL or response and decide whether to retry the request.

const fetchWithRetry = fetchRetry(fetch, {
retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000),
retryOn: (attempt, error, response) => {
const shouldRetry
= (attempt: number, error: Error | null, response: Response | null) =>
attempt < 3
&& response
&& response.status == 520 // Cloudflare errors
&& response.url.includes('rpc/your_database_function')
if (shouldRetry(attempt, error, response)) {
console.log(`Retrying request... Attempt #${attempt}`, response)
return true
}
return false
}
})
async function yourDatabaseFunction() {
const { data, error } = await supabase
.rpc('your_database_function', { param1: 'value1' });
if (error) {
console.log('Error executing RPC:', error);
} else {
console.log('Response:', data);
}
}
yourDatabaseFunction();

通过将 retryOn 与自定义函数一起使用,你可以为重试请求定义具体的条件。在这个例子中,重试逻辑仅应用于针对特定数据库函数的请求。

🌐 By using retryOn with a custom function, you can define specific conditions for retrying requests. In this example, the retry logic is applied only to requests targeting a specific database function.

结论 #

🌐 Conclusion

对于大多数用例,内置的 PostgREST 重试机制已经足够使用。只有在需要对非 PostgREST 请求重试或需要对重试行为进行精细控制时,才使用 fetch-retry。

🌐 For most use cases, the built-in PostgREST retry mechanism is sufficient. Use fetch-retry when you need retries on non-PostgREST requests or need fine-grained control over retry behavior.