Skip to content

fix(examples): forward abort signal in tanstack-db-web-starter Electric proxy - #4768

Open
Jaime02 wants to merge 1 commit into
electric-sql:mainfrom
Jaime02:fix/electric-proxy-forward-abort-signal
Open

fix(examples): forward abort signal in tanstack-db-web-starter Electric proxy#4768
Jaime02 wants to merge 1 commit into
electric-sql:mainfrom
Jaime02:fix/electric-proxy-forward-abort-signal

Conversation

@Jaime02

@Jaime02 Jaime02 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Problem

proxyElectricRequest calls fetch(originUrl) without forwarding the incoming request's AbortSignal. When a client goes away mid-request — a page reload, a navigation, a closed tab — the proxy's upstream call to Electric has no cancellation path and keeps running to completion.

For live=true long-polls that is the full long-poll timeout. Measured against a local Electric (electricsql/electric:latest, default settings), proxying through a TanStack Start route:

unsignalled upstream long-poll held open for: 20004 ms  (status 200)
signalled upstream released after:                1 ms  (AbortError)

Each abandoned live request pins one upstream connection and one fetch slot for ~20s after the client that wanted it is already gone.

This compounds with the concurrency limit that skills/electric-proxy-auth/SKILL.md already documents:

Bun caps simultaneous fetch() calls at 256 per process by default. Excess requests queue silently — the proxy keeps accepting inbound connections but upstream calls to Electric stall, surfacing as latency spikes rather than errors.

A page holding ~10 shapes leaks ~10 slots per reload, each for ~20s. Roughly 26 abandoned page loads inside one 20-second window is enough to exhaust the pool — easily reached when a deploy causes many connected clients to reconnect at once. The symptom is the latency spike the skill describes; the missing signal is one of its causes.

Change

Forward the request's AbortSignal to the upstream fetch:

export async function proxyElectricRequest(
  originUrl: URL,
  signal?: AbortSignal
): Promise<Response> {
  const response = await fetch(originUrl, { signal })

and pass request.signal at the three call sites (todos, users, projects).

The parameter is optional, so this is source-compatible with any existing caller.

Same pattern elsewhere

I kept this PR to the one starter to stay reviewable, but the same fetch(originUrl) without a signal appears in:

  • examples/tanstack-db-expo-starter/api/index.ts (~line 138)
  • website/docs/sync/guides/auth.md (proxy examples around lines 152, 407, 414, 624, 644)
  • packages/typescript-client/skills/electric-proxy-auth/SKILL.md (~line 51)

…ic proxy

`proxyElectricRequest` called `fetch(originUrl)` without the incoming
request's `AbortSignal`, so a client disconnect left the upstream call to
Electric with no cancellation path. For `live=true` long-polls that holds a
connection and a fetch slot for the full long-poll timeout (~20s measured)
after the client is gone, which compounds with the 256-concurrent-fetch cap
that skills/electric-proxy-auth/SKILL.md documents.

Forward the signal through to the upstream fetch and pass `request.signal`
at the three call sites. The parameter is optional, so existing callers are
unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Jaime02
Jaime02 marked this pull request as ready for review August 22, 2026 17:00
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.

1 participant