Reconnect backoff has no jitter (recorded, not yet due) #19
Labels
No labels
area:defold
area:docs
area:infra
area:protocol
area:testing
kind:bug
kind:chore
phase:breadth
phase:core
phase:hardening
phase:slice
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
yuris/spacetimedb-defold#19
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
stdb/connection.lua:203carries a deliberate deferral:The trigger named there has not fired — nothing is stampeding anything — so this issue is a record, not a request to go implement it. Filing it because CI just produced the first real evidence that the reconnect path runs longer than a workstation suggests, which makes the ceiling worth writing down before someone ships a game on it.
The evidence
backoff_delayisbase * 2^(attempt-1)capped atcap, with no random component: every client that loses the same server reconnects on the same schedule, to the millisecond, forever.Locally a server restart is absorbed in one attempt. On the CI runner, run #38 took four:
That is the backoff working correctly. The point is the shape of it: a ~13s outage window is entirely normal for a real server restart, and during that window every connected client is retrying in lockstep at 1s, 2s, 4s, 8s… Each attempt is a fresh websocket upgrade plus a fresh
IdentityTokenround trip plus a resubscribe of every query the client had, so the herd arrives all at once precisely when the server is least able to absorb it — and a rejected retry pushes the whole herd to the next slot together.Single-player-scale usage will never notice. A few hundred clients restarting against one module is where synchronized retries stop being theoretical.
Fix, when the trigger fires
Full jitter in
backoff_delay, which is already a pure function with tests, so this is a contained change:Two consequences to handle rather than discover:
math.randommakes the function impure, and the existing tests assert exact delays. Either inject the RNG as an argument defaulting tomath.random(matching howstorageandis_html5are already injectable seams), or assert on the range instead of the value. The seam is more consistent with the rest of the SDK.math.randomseedis per-process; Defold seeds it lazily. Without an explicit seed every client picks the same "random" spread, which reproduces the exact problem being fixed. This is the part that actually bites, and the reason not to treat jitter as a one-liner.Not doing now, deliberately
The current behaviour is correct, tested, and adequate for every use this SDK has. Adding an RNG seam plus seeding plus range-based tests to a working backoff, on the strength of a load nobody is applying, buys nothing today and costs a permanently more complicated function.
Reasons to reopen the decision: a deployment with more than a few dozen concurrent clients, an observed retry storm after a module publish, or any report of reconnects failing in bursts rather than individually.