Skip to content

Add client-side network resilience to web app#1394

Merged
joshunrau merged 4 commits into
DouglasNeuroInformatics:mainfrom
joshunrau:dev
Jul 9, 2026
Merged

Add client-side network resilience to web app#1394
joshunrau merged 4 commits into
DouglasNeuroInformatics:mainfrom
joshunrau:dev

Conversation

@joshunrau

Copy link
Copy Markdown
Collaborator

Summary

The app runs on an internal hospital network (packet loss, DPI overload, mid-flight connection resets, unannounced DNS changes) behind an appliance we don't control that intermittently emits 502s / drops connections on /api/* XHR calls. Previously every such blip fired a scary HTTP Request Failed / raw-502 error toast — and a render-blocking failure dumped users on the terminal "Something Went Wrong" page.

This adds a client-side resilience layer to apps/web so transient failures are retried and hidden from users (graceful-UX only; no infra changes).

Changes

  • services/axios.ts — retry idempotent requests only (GET/HEAD/OPTIONS; never writes, to avoid duplicate submissions) on transient failures (no-response/ERR_NETWORK/timeout, or 502/503/504). Jittered exponential backoff, bounded by a ~15s time budget, and offline-aware (waits for the browser online event instead of burning retries while navigator.onLine is false). On final give-up it shows a calm "Connection Problem" message rather than a raw status code. meta.disableRetry opts a request out.
  • services/react-query.tsqueries.retry: false so React Query no longer compounds axios's retries.
  • store/slices/connectivity.slice.ts (+ types.ts, index.ts) — pendingRetries counter + isOnline, driving…
  • components/ConnectivityBanner.tsx — a subtle non-blocking pill ("Reconnecting…" / "Offline — waiting for connection…").
  • components/AppErrorComponent.tsx (wired as router defaultErrorComponent) — for transient errors, a self-healing screen that auto-recovers when the browser comes back online (plus manual "Try again"); genuine errors still fall through to the existing ErrorPage.

Scope / notes

  • apps/web only. The gateway (patient self-administer) app is intentionally untouched — to be audited separately for equivalent client-side API calls.
  • Writes are never auto-retried by design (duplicate-submission safety); they get the friendly message and the user re-submits.
  • Timings are one-line tunables in services/axios.ts (RETRY_BUDGET_MS, BASE_RETRY_DELAY_MS, MAX_RETRY_DELAY_MS, MAX_OFFLINE_WAIT_MS).

Verification

  • pnpm --filter @opendatacapture/web lint (tsc + eslint) ✅
  • pnpm exec vitest run --project web — 29 tests ✅
  • Manual: DevTools → Network → Offline mid-navigation shows the banner and (for blocking loads) the recovery screen, then auto-recovers on Online.

🤖 Generated with Claude Code

joshunrau and others added 2 commits July 9, 2026 12:40
The app runs on a flaky hospital network (packet loss, DPI overload,
mid-flight connection resets, unannounced DNS changes) behind an appliance
that intermittently emits 502s on /api/* calls. Handle these gracefully in
apps/web instead of showing scary error toasts.

- axios: retry idempotent requests (GET/HEAD/OPTIONS only, never writes) on
  transient failures (no-response/ERR_NETWORK/timeout, 502/503/504) with
  jittered exponential backoff, bounded by a ~15s time budget and pausing for
  the browser `online` event while offline; friendly "Connection Problem"
  toast on give-up instead of a raw status code
- react-query: disable query retry so it doesn't compound axios retries
- connectivity store slice: pendingRetries + isOnline, driving a subtle
  ConnectivityBanner ("Reconnecting…" / "Offline…")
- AppErrorComponent: router defaultErrorComponent that shows a self-healing
  screen (auto-recovers on `online`) for transient errors, falling through to
  the existing ErrorPage for genuine errors

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gdevenyi

gdevenyi commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

This is great

@gdevenyi

gdevenyi commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

This PR also known as "making up for TCP being misconfigured"

@joshunrau joshunrau merged commit e943b55 into DouglasNeuroInformatics:main Jul 9, 2026
1 check 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.

2 participants