fix(gateway): keep the record ring small now that aggregates scan everything

The gateway still built Stats with NewStats(10000), a leftover from when the
ring WAS the source of the dashboard's numbers. With aggregates now computed
from the full audit history, a 10000-entry ring only means 10000 resident Req
structs — the live instance came up at 64 MB instead of ~40 MB, putting back
most of the memory the on-demand paging work removed.

The ring's only jobs are the status page's 5-minute SourceRecent /
SourceAverages windows and the dashboard's first screen, both of which fit in
defaultRingSize (500). Older records are paged from disk.

TestGatewayRingStaysSmall pins it so the constant cannot drift back up.
This commit is contained in:
JianFeeeee
2026-08-30 09:34:25 +08:00
parent 3ddae41f0c
commit 5b6d6fc90d
2 changed files with 23 additions and 1 deletions

View File

@ -999,3 +999,19 @@ func TestCannotDeleteOwnKey(t *testing.T) {
t.Errorf("unexpected message: %s", rr.Body.String())
}
}
// TestGatewayRingStaysSmall pins the resident record ring at the small default.
// The gateway used to construct Stats with a 10000-record ring, which after the
// full-history aggregate scan meant 10000 resident Req structs — putting back the
// ~25 MB the on-demand paging work removed. Aggregates cover all of history;
// the ring only needs the first screen plus the 5-minute status windows.
func TestGatewayRingStaysSmall(t *testing.T) {
g := newTestGateway(t)
g.stats.mu.Lock()
max := g.stats.maxRecs
g.stats.mu.Unlock()
if max != defaultRingSize {
t.Fatalf("gateway record ring = %d, want %d (a big ring reintroduces the resident-memory cost)",
max, defaultRingSize)
}
}

View File

@ -120,7 +120,13 @@ func New(c *core.Core, gatewayKeys []string) (*Gateway, error) {
if err != nil {
return nil, err
}
st := NewStats(10000)
// The record ring is deliberately small: aggregates are built from the full
// audit history at startup (see Stats.LoadAudit), so the ring only has to
// cover the status page's 5-minute source windows and the dashboard's first
// screen. Everything older is paged from disk by /api/stats/records.
// A large ring here would put the ~25 MB of resident Req structs straight
// back, which is exactly what the on-demand paging removed.
st := NewStats(defaultRingSize)
if cfg := c.Config(); cfg != nil && cfg.RuntimeFile != "" {
st.LoadAudit(cfg.RuntimeFile + ".audit.jsonl")
}