From a75b3469a3575ea81444cad680b0180bc998709d Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 15 Mar 2026 08:58:13 +0000 Subject: [PATCH] Always retry forever --- CLAUDE.md | 2 +- frontend/sync-client/src/services/sync-service.ts | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index eb33cc1d..bc2cd1d7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -303,7 +303,7 @@ When the server broadcasts updates via WebSocket: 7. **Key resolution with stale documentIds**: When `resolveIdempotencyKeys` returns a documentId, check `getDocumentByDocumentId` first. If another document already has that ID (assigned through normal sync), remove the stale pending doc instead of creating a duplicate. -8. **`resolveIdempotencyKeys` must not use `retryForever`**: The HTTP call to `/documents/resolve-keys` is an optimization. If it fails (e.g., SyncReset aborts the fetch), return an empty map and let the pending creates retry normally with their keys. Using `retryForever` can cause deadlocks — the sync pipeline stalls waiting for the retry while the WebSocket is disconnected. +8. **`resolveIdempotencyKeys` uses `retryForever`**: The HTTP call to `/documents/resolve-keys` retries forever like all other sync service calls. `SyncResetError` is re-thrown by `retryForever`, so the pipeline properly aborts on WebSocket disconnect without deadlocking. ### E2E Test Configuration diff --git a/frontend/sync-client/src/services/sync-service.ts b/frontend/sync-client/src/services/sync-service.ts index a0b67830..acac8958 100644 --- a/frontend/sync-client/src/services/sync-service.ts +++ b/frontend/sync-client/src/services/sync-service.ts @@ -375,7 +375,7 @@ export class SyncService { `Resolving ${keys.length} idempotency keys` ); - try { + return this.retryForever(async () => { const response = await this.client( this.getUrl("/documents/resolve-keys"), { @@ -386,12 +386,11 @@ export class SyncService { ); if (!response.ok) { - this.logger.warn( + throw new Error( `Failed to resolve idempotency keys: ${await SyncService.errorFromResponse( response )}` ); - return new Map(); } const result: { resolved: Record } = @@ -406,12 +405,7 @@ export class SyncService { ); return resolved; - } catch (e) { - this.logger.warn( - `Failed to resolve idempotency keys: ${e}` - ); - return new Map(); - } + }); } public async ping(): Promise {