如何用 supabase-js 做自动重试
Learn how to configure automatic retries for your Supabase API requests.
重要
你应该只有在请求因网络错误(例如 Cloudflare 的 520 状态)失败时才启用重试。大量重试可能会耗尽 Data API 连接池,这可能导致吞吐量降低和请求失败。
🌐 You should only enable retries if your requests fail with network errors (e.g. 520 status from Cloudflare). A high number of retries have the potential to exhaust the Data API connection pool, which could result in lower throughput and failed 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-retry2. 封装 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-retryconst fetchWithRetry = fetchRetry(fetch)// Create a Supabase client instance with the custom fetchconst 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.