pub struct RefreshCoalescer<T> { /* private fields */ }Expand description
Runs one refresh at a time; a refresh asked for while another is in flight joins it instead of issuing a second.
04-subsystem-contracts.md: “Manual refresh coalesces with an in-flight
request.” The requirement is a budget one before it is a latency one — F5
held down on the dashboard would otherwise be an operator-driven denial of
service against a 5,000/hour ceiling shared with the polling that keeps
runners starting.
The mechanism is the generation-and-gate pattern
crate::AuthenticatedClient::revalidate already uses for single-flight
re-validation, and it is here rather than there because the two coalesce
different things. A caller samples the generation before queuing on the
gate; if it moved while the caller waited, some other refresh covered it and
this one returns that result without calling work at all. work being
FnOnce is what makes “no second request” structural rather than
remembered: the joining path never has a future to poll.
§One instance per target. This is a requirement, not a convention
last is a single slot and generation is a single counter, so an instance
can only ever be a cache of one thing. Sharing one coalescer across two
targets does not merely lose cache hits — it hands target A’s caller target
B’s snapshot, silently and with no error, because joining a generation that
moved is precisely how this type reports “somebody else already refreshed
what you asked for”. Nothing here can detect that the somebody else was
refreshing something different.
e1 and g2 therefore hold one instance per ScaleTarget — keyed by
target in whatever map they already keep — and never one per host. The type
cannot enforce it, which is exactly why it is written down.