Skip to content

fix(api): retry safe requests rejected by the per-user concurrency limit - #339

Merged
stefan-ernst merged 1 commit into
Windshiftapp:mainfrom
Pilanda-ERP:fix/api-retry-concurrency-limit
Oct 14, 2026
Merged

stefan-ernst merged 1 commit into
Windshiftapp:mainfrom
Pilanda-ERP:fix/api-retry-concurrency-limit

Conversation

@dpb97

@dpb97 dpb97 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #338

The per-user concurrency limiter answers bursts with 429 + Retry-After: 1, but the API client surfaced that as a hard failure. On collection boards this broke the item detail fallback (six parallel reference reads via Promise.all, see f9752b0) and left pickers empty.

Change

  • performFetchWithRetry() wraps performFetchAPI() in fetchFromAPI():
    • retries GET/HEAD/OPTIONS up to 2 times on 429
    • delay = Retry-After (seconds) when present, otherwise 500 ms · 2^attempt; capped at 5 s, plus up to 250 ms jitter so parallel requests spread out
    • stops waiting immediately when the caller's AbortSignal fires (keeps superseded loaders cheap)
  • Writes are never retried.
  • In-flight GET de-duplication is unchanged: duplicate callers share the single (retried) request.
  • createApiError() now records retryAfter from the response header.

Tests

frontend/src/lib/api/core.spec.js (Vitest): retry then success, give up after the bound and surface the 429, no retry for PATCH, abort while waiting, delay calculation.
Full suite locally: 92/93 – the remaining failure (i18n-utils.spec.js > uses the active application locale, timeout) also fails on unmodified main on my machine.
biome check clean for both files.

Notes

  • This deliberately lives in the API client rather than in individual stores, so every fan-out view benefits.
  • Not addressed here: reducing the fan-out itself on boards (e.g. loading milestones once per board instead of per card) – happy to look at that separately.

I have read and agree to the CLA.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@dpb97

dpb97 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

The per-user concurrency limiter answers request bursts with
429 Too Many Requests and Retry-After: 1. The API client surfaced that as a
hard failure, so views that fan out many reads at once broke intermittently:
on collection boards the item detail fallback (which now hydrates six
reference lists in parallel) failed with "Too many concurrent requests"
instead of rendering, and pickers loaded empty.

Retry GET/HEAD/OPTIONS up to twice on 429, honouring Retry-After (capped at
5s, jittered), and stop waiting when the caller aborts. Writes are never
retried. In-flight GET de-duplication keeps sharing a single retried request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dpb97
dpb97 force-pushed the fix/api-retry-concurrency-limit branch from a00854d to 78cb299 Compare October 14, 2026 06:39
github-actions Bot added a commit that referenced this pull request Oct 14, 2026
@stefan-ernst
stefan-ernst merged commit 1a603ea into Windshiftapp:main Oct 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Frontend treats 429 from the per-user concurrency limiter as a hard failure

2 participants