Skip to content

fix(ca): stop scanning every environment on startup - #1056

Merged
codyde merged 1 commit into
masterfrom
cody/ca-rate-limit
Aug 9, 2026
Merged

fix(ca): stop scanning every environment on startup#1056
codyde merged 1 commit into
masterfrom
cody/ca-rate-limit

Conversation

@codyde

@codyde codyde commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

A user with several workspaces got rate limited opening railway ca. Startup asked for agents in every environment of every project of every workspace, one request each — 361 on a six-workspace account, on every launch, uncached. cloudAgents requires an environmentId, so the fan-out is forced by the query; doing it for the whole account at startup was not.

Startup now loads only what a keypress immediately needs: the prompt's target, the default project's environments, and environments this machine has launched an agent in, from the CLI's own config. That's two or three requests, and everything else loads when its row is expanded, which the tree already did. shift+r runs the old whole-account scan on request — that's how an agent created elsewhere (another machine, the dashboard, a project you've never opened) still gets found, with the cost spent when asked for rather than charged to every launch.

Rate limits are handled rather than absorbed. The first 429 stops the rest of the batch instead of spending the remaining budget on requests that will also be refused. Environments still in flight go back to "not loaded," so opening one retries instead of spinning forever. And Retry-After, which backboard sets on every 429 and the CLI discarded, is now surfaced: "Rate limited — try again in 43s."

For context, the limiter is 1,000 requests per hour, keyed on the token's workspace or user, and only applies to API-token auth — railway login sessions are exempt, RAILWAY_API_TOKEN is not. At 360 environments, three launches on a token exceed it.

The real fix is server-side and lands separately: railwayapp/mono#34876 adds myCloudAgents, a user-scoped listing that answers "where are my agents" in one query. Once it deploys, a follow-up PR makes it the primary startup path and retires shift+r.

Verification

869 tests, fmt and clippy clean. New tests cover: startup loads only target, default-project, and known environments, claiming each once; shift+r scans the rest; and a rate limit releases what was in flight so a retry works.

🤖 Generated with Claude Code

A user with several workspaces got rate limited opening `railway ca`. The
startup sweep asked for agents in every environment of every project of every
workspace, one request each: 6 workspaces of 30 projects with 2 environments is
361 requests before the tree finishes drawing, on every launch, uncached. There
is no workspace- or user-scoped listing to ask instead — `cloudAgents` requires
an environment ID — so the fan-out was forced by the query, but doing it for the
whole account at startup was not.

Startup now loads only what a keypress immediately needs:

  - the prompt's target, which New Session reads to decide whether it has an
    agent to work on
  - the default project, which the tree leads with
  - environments this machine has launched an agent in, from the CLI's own
    records, so your own work is where you left it

That is two or three requests instead of hundreds. Everything else loads when
its row is expanded, which the tree already did.

`shift+r` runs the old whole-account scan on request, which is how an agent
made elsewhere — another machine, the dashboard, a project you have never
opened — still gets found without expanding projects one at a time. The cost is
the user's to spend rather than charged to every launch.

Rate limits are now handled rather than absorbed:

  - a 429 in any background fetch stops the rest of its batch, instead of
    spending the remaining budget on requests that will also be refused
  - environments still in flight go back to "not loaded", so opening one
    retries rather than showing a spinner that never resolves
  - `Retry-After`, which backboard sets on every 429, is read and reported:
    "Rate limited — try again in 43s" rather than "please try again later"

The real fix is server-side and small: `CloudAgent` rows carry `userId` and
`projectId`, so "every agent I own" is one indexed query. A user-scoped listing
would make counts-everywhere cost one request instead of hundreds, and retire
`shift+r`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codyde codyde added the release/patch Author patch release label Aug 7, 2026
@codyde
codyde merged commit 481c58d into master Aug 9, 2026
8 checks passed
@codyde
codyde deleted the cody/ca-rate-limit branch August 9, 2026 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release/patch Author patch release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant