Respect Gmail retry-after in messaging throttle (#17850)

Gmail 429/403 rate-limit responses include an explicit retry-after
timestamp, usually ~15 minutes out.

The exponential backoff starts at 1 minute, so the channel burns through
all 5 retry attempts before the window actually closes and gets marked
as permanently failed.

Adds throttleRetryAfter to the message channel and uses max(backoff,
retryAfter) in isThrottled().
This commit is contained in:
neo773
2026-02-13 22:50:37 +05:30
committed by GitHub
parent 84afbb4d2c
commit d54b713264
21 changed files with 1235 additions and 866 deletions
@@ -116,6 +116,7 @@ export class MessageChannelSyncStatusService {
syncCursor: '',
syncStageStartedAt: null,
throttleFailureCount: 0,
throttleRetryAfter: null,
pendingGroupEmailsAction: MessageChannelPendingGroupEmailsAction.NONE,
});
@@ -225,6 +226,7 @@ export class MessageChannelSyncStatusService {
syncStatus: MessageChannelSyncStatus.ACTIVE,
syncStage: MessageChannelSyncStage.MESSAGE_LIST_FETCH_PENDING,
throttleFailureCount: 0,
throttleRetryAfter: null,
syncStageStartedAt: null,
syncedAt: new Date().toISOString(),
});
@@ -307,6 +309,7 @@ export class MessageChannelSyncStatusService {
await messageChannelRepository.update(messageChannelIds, {
syncStage: MessageChannelSyncStage.FAILED,
syncStatus: syncStatus,
throttleRetryAfter: null,
});
const metricsKey =
@@ -98,6 +98,7 @@ export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity {
syncStage: MessageChannelSyncStage;
syncStageStartedAt: string | null;
throttleFailureCount: number;
throttleRetryAfter: string | null;
connectedAccount: EntityRelation<ConnectedAccountWorkspaceEntity>;
connectedAccountId: string;
messageChannelMessageAssociations: EntityRelation<