Skip to content

Analysis gateway: a share per client when places are scarce - #574

Merged
adamjohnwright merged 3 commits into
mainfrom
fix/gateway-fairness
Oct 20, 2026
Merged

adamjohnwright merged 3 commits into
mainfrom
fix/gateway-fairness

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

Spec 010 Story 6 (specs/010-java-services, T065). From the review of everything merged since #485.

The problem. The gateway's lanes and waiting list were first come, first served across all clients. One address keeping a lane and its waiting list full (4 running, 40 waiting) got every other reader refused for as long as it kept them full.

The fix: a share per client, only when places are scarce.

  • A client has at most PER_CLIENT (default 8) computations running or waiting, across all lanes.
  • Beyond that, a request that would have to wait is refused (503 with Retry-After), while other clients still get in.
  • A request that finds a place free still runs, so a class or an institution behind one address is never refused by an idle service.
  • A client is the address nginx saw, from X-Real-IP. nginx sets it from the connection, and the gateway listens on loopback, so only nginx can send it. An IPv6 client is grouped by its /64, since it can pick any address in it.
  • /health reports the share and how many clients are inside.

Not included. The first draft also closed the connection after a refusal. The review showed that is unnecessary behind nginx, which sends the body whole so Node discards it. It could also cut a large refused upload mid-send and turn the 503 into nginx's own 502, so it is not part of this PR.

Checks

  • Gateway specs: 31 passed. Each rule was shown failing its spec when mutated away: the share itself, holding the share back while places are free, and the place given back on a timeout and on leaving.
  • On beta, rebuilt: /health shows perClient: 8. AnalysisService GETs through nginx and the gateway answer as before.

🤖 Generated with Claude Code

adamjohnwright and others added 3 commits October 20, 2026 19:36
From the review of everything merged since #485 (spec 010 Story 6, T065).

The lanes' places and waiting list were first come, first served across
all clients, so one address keeping a lane and its waiting list full had
everyone else refused. Now a client has at most PER_CLIENT (default 8)
computations running or waiting, in all lanes; beyond that, one that
would have to wait is refused, while one that finds a place free still
runs -- a class or an institution behind one address is not refused by
an idle service.

A client is the address nginx saw (X-Real-IP, which nginx sets from the
connection; the gateway listens on loopback, so only nginx can send it),
and an IPv6 client its /64, any address in which it can choose. /health
reports the share and how many clients are inside.

Each rule shown failing its spec when mutated away: the share, the share
held back while places are free, and the place given back on a timeout
and on leaving.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adamjohnwright
adamjohnwright merged commit 7a4569d into main Oct 20, 2026
7 checks passed
@adamjohnwright
adamjohnwright deleted the fix/gateway-fairness branch October 20, 2026 20:14
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