fix: Retry Notion API 5xx errors with exponential backoff (#12481)

The Notion API can return transient 5xx errors during imports. Retry these
up to 8 times with exponential backoff, tracked separately from the existing
timeout/rate-limit retry budget.
This commit is contained in:
Tom Moor
2026-05-26 20:38:12 -04:00
committed by GitHub
parent 84c00cfae7
commit 667bfe68c5
+29
View File
@@ -6,6 +6,7 @@ import {
isFullPageOrDatabase,
isFullUser,
RequestTimeoutError,
UnknownHTTPResponseError,
} from "@notionhq/client";
import type {
BlockObjectResponse,
@@ -60,6 +61,7 @@ export class NotionClient {
private limiter: ReturnType<typeof RateLimit>;
private pageSize = 100;
private maxRetries = 3;
private maxServerErrorRetries = 8;
private retryDelay = 1000;
private skipChildrenForBlock = [
"unsupported",
@@ -94,6 +96,7 @@ export class NotionClient {
*/
private async fetchWithRetry<T>(apiCall: () => Promise<T>): Promise<T> {
let retries = 0;
let serverErrorRetries = 0;
// oxlint-disable-next-line no-constant-condition
while (true) {
@@ -149,6 +152,32 @@ export class NotionClient {
);
}
// Check if this is a server-side error (5xx) — Notion's API can be
// unreliable, so retry these for longer with exponential backoff.
if (
(error instanceof APIResponseError ||
error instanceof UnknownHTTPResponseError) &&
error.status >= 500
) {
if (serverErrorRetries < this.maxServerErrorRetries) {
serverErrorRetries++;
const delay = this.retryDelay * 2 ** (serverErrorRetries - 1);
Logger.info(
"task",
`Notion API returned ${error.status}, retrying in ${delay}ms (retry ${serverErrorRetries}/${this.maxServerErrorRetries})`
);
// Wait before retrying
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
Logger.warn(
`Notion API returned ${error.status} after ${this.maxServerErrorRetries} retries`,
{ error: error.message }
);
}
// Re-throw the error if it's not a rate limit issue or we've exhausted retries
throw error;
}