Skip to content

ateclient: spread RPCs over every ateapi replica - #1319

Merged
Eitan Yarmush (EItanya) merged 1 commit into
agent-substrate:mainfrom
BenTheElder:ateclient-round-robin
Aug 30, 2026
Merged

ateclient: spread RPCs over every ateapi replica#1319
Eitan Yarmush (EItanya) merged 1 commit into
agent-substrate:mainfrom
BenTheElder:ateclient-round-robin

Conversation

@BenTheElder

@BenTheElder Benjamin Elder (BenTheElder) commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

ateapi is a headless Service, so its DNS name resolves to one address per replica and the client picks. This one asked for no policy, which means gRPC's pick_first: it connects to whichever address answers first and sends everything there for the life of the connection.

So a client talks to one replica however many are running, and adding replicas moves no load. Measured with eight load generators against two replicas, one took 97% of the traffic.

internal/ateapiauth, which atelet and the controllers dial through, has asked for round_robin all along. This is the same policy for the clients that do not.

Pulled out from #1266, I ran into this while doing some custom benchmarking using ateclient, but this is already a bug for kubectl-ate, demos, ...

  • Tests pass
  • Appropriate changes to documentation are included in the PR

AI-assisted.

// ateapi is a headless Service, so that is one address per replica, and gRPC's
// default of pick_first would send an entire client's traffic to whichever one
// it connected to first. internal/ateapiauth dials with the same policy.
const roundRobinServiceConfig = `{"loadBalancingConfig": [{"round_robin":{}}]}`

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This verbatim the config we use in internal/ateapiauth.

We could dedupe them but that seemed unnecessary for now. If this becomes more complex or we need N+1 client packages we probably should at that point.

@BenTheElder Benjamin Elder (BenTheElder) added kind/bug Something isn't working / bugfixes area/api-machinery labels Aug 29, 2026
A client that asks for no load balancing policy gets gRPC's pick_first: it
sends every RPC to whichever address it connected to first, for the life of
that connection. So a client talks to one replica however many are running,
and adding replicas moves no load. Measured with eight load generators against
two replicas, one took 97% of the traffic.

The policy is independent of where the addresses come from. internal/ateapiauth,
which atelet and the controllers dial through, sets round_robin alongside the
k8s EndpointSlice resolver for exactly this reason. ateclient resolves its
target through gRPC's built-in resolver rather than that one, but either way
the addresses are useless without a policy that spreads over them.
@EItanya
Eitan Yarmush (EItanya) merged commit 6cd878d into agent-substrate:main Aug 30, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api-machinery kind/bug Something isn't working / bugfixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants