Always retry forever

This commit is contained in:
Andras Schmelczer 2026-03-15 08:58:13 +00:00
parent 2e827b6da5
commit a75b3469a3
2 changed files with 4 additions and 10 deletions

View file

@ -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

View file

@ -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<string, string> } =
@ -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<PingResponse> {