Skip to content

feat(discovery)!: spread joins across lobbies instead of packing one - #71

Merged
hbrombeer merged 2 commits into
mainfrom
feat/spread-lobbies
Aug 3, 2026
Merged

feat(discovery)!: spread joins across lobbies instead of packing one#71
hbrombeer merged 2 commits into
mainfrom
feat/spread-lobbies

Conversation

@hbrombeer

Copy link
Copy Markdown
Member

Joins go to the least-occupied lobby, always.

Why

The previous policy packed the fullest lobby below a soft cap, with a good
reason stated in the code: a network of 50 should feel like one lobby of 50,
not five of ten. In practice the cap defaulted to 400 and no region ever came
close, so every player in a region sat in a single process.

Measured on stage under load, the lobby was never the reason to split:

players in the one lobby 228
lobby CPU 0.29 cores
lobby tick (avg) 2 ms against a 50 ms budget
the other lobby 0 players

The reason to split is blast radius, not load — one restart took the whole
region's players with it. That argues for spreading always rather than for a
threshold nobody reaches.

Autoscaling falls out of the same rule

A lobby added by the FleetAutoscaler is empty, so it is the least occupied, so
it takes joins until it has caught up. No special case for "new lobby".

Verified on stage before this change, using the soft cap as a stand-in: with
the cap lowered to 150, joins moved to the second lobby (152/48) and the Fleet
scaled 2 → 3 on its own. This change makes that the default behaviour without a
threshold.

Breaking

GROUNDS_AGONES_LOBBY_SOFT_CAP is removed. Deployments that set it keep
working — the value is ignored — but groundsgg/deploy should drop it, since
it was only just added for the experiment above.

LobbyPacking becomes LobbySelection; the name was describing the old policy.

Trade-off worth naming

This reverses a deliberate product decision. With the Buffer FleetAutoscaler
keeping one Ready lobby spare, always-spreading means that spare starts taking
players immediately, which allocates it, which makes the autoscaler add
another — so a region will tend to sit at maxReplicas (4 today) rather than
at the minimum. That is more small lobbies rather than one big one, which is
exactly the intent, but it is a visible change to how the network feels.

Joins now go to the least-occupied lobby, always. The previous policy packed
the fullest lobby below a soft cap so that a network of 50 would feel like one
lobby of 50 rather than five of ten — a real concern, but the effect was that
every player in a region sat in one process, and the cap defaulted to 400,
which no region ever reached.

Measured on stage, the lobby was never the reason to split: 228 players cost
0.29 cores and a 2 ms average tick against a 50 ms budget. The reason is blast
radius — one restart took every player in the region with it. That argues for
spreading always, not for a threshold nobody reaches.

A newly autoscaled lobby needs no special case: it is empty, so it is the least
occupied, so it takes joins until it has caught up. Priority filling falls out
of the same rule that does the spreading.

BREAKING CHANGE: GROUNDS_AGONES_LOBBY_SOFT_CAP is gone. Deployments setting it
keep working, the value is simply ignored; groundsgg/deploy should drop it.
@sonarqubecloud

sonarqubecloud Bot commented Aug 3, 2026

Copy link
Copy Markdown

@hbrombeer
hbrombeer marked this pull request as ready for review August 3, 2026 12:05
@hbrombeer
hbrombeer merged commit 79b57c8 into main Aug 3, 2026
3 checks passed
@hbrombeer
hbrombeer deleted the feat/spread-lobbies branch August 3, 2026 12:08
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