diff --git a/docs/GatewayDashboardDesign.md b/docs/GatewayDashboardDesign.md index 0beb73a..d2327fa 100644 --- a/docs/GatewayDashboardDesign.md +++ b/docs/GatewayDashboardDesign.md @@ -394,6 +394,18 @@ its lease expires. One session means one worker process backs every dashboard circuit; all access is serialised so the worker sees one in-flight command at a time. Tag reads go through `GatewaySession.SubscribeBulkAsync` / `ReadBulkAsync`. +The advise set that backs those reads is capped at 256 tags (one browse page plus +headroom) and evicted least-recently-read-first. Without the cap every tag any +viewer ever inspected stayed advised on the single dashboard worker until the +session faulted, so browsing a large galaxy accreted unbounded live MXAccess +subscriptions — and the event churn they feed — on one x86 process. Reading a tag +already in the set marks it most-recently-read; subscribing past the cap unadvises +the oldest entries with `GatewaySession.UnsubscribeBulkAsync` in one batch before +the new ones are advised. Tags read in the same call are never evicted to make +room for each other. A failed unadvise does not fail the read: the tags are +dropped from tracking anyway (they re-subscribe if read again), because the +session-invalidation path already handles gateway/worker drift. + The Alarms page does **not** use the dashboard session: alarm data comes from the gateway's always-on central monitor. `QueryAlarmsAsync` reads `IGatewayAlarmService.CurrentAlarms` — the monitor's in-process cache — so the