Make metrics reflect autoscaling policies (Refs #137)
CI / checks (push) Successful in 4m49s

This commit is contained in:
2026-10-10 14:48:52 -04:00
parent bd34c3c9e7
commit 33da4482a6
24 changed files with 1264 additions and 370 deletions
+28 -13
View File
@@ -6,7 +6,7 @@
import { timeZone } from '$ui/stores/time-zone.js';
import { createTimeFormatter } from '$lib/time-zone.js';
import { pollVisible } from '$ui/poll.js';
import { metricDuration } from '$ui/metrics.js';
import { metricDuration, metricNumber } from '$ui/metrics.js';
import { createMetricsRefresh } from '$ui/metrics-refresh.js';
import SectionHeader from '$ui/components/primitives/SectionHeader.svelte';
import Card from '$ui/components/primitives/Card.svelte';
@@ -301,8 +301,8 @@
</p>
{/if}
{#if report.summary.observed === 0}<p class="notice">
All captured server status is unknown. A dash means occupancy could not be
calculated; it does not mean servers were empty.
All captured lobby status is unknown. Running counts include these lobbies, but
their occupancy and availability could not be determined.
</p>{/if}
<MetricsChart points={report.points} days={report.days} timeZone={report.scope.timeZone} />
{/if}
@@ -316,7 +316,7 @@
tabs={[
{ id: 'maps', label: 'Maps' },
{ id: 'instances', label: 'Instances' },
{ id: 'insights', label: 'Hosting insights' }
{ id: 'insights', label: 'Autoscaling signals' }
]}
value={view}
onchange={changeView}
@@ -364,15 +364,28 @@
<p>
Previous window: {format.period(report.previous.since)} – {format.period(
report.previous.until
)}. Known time: {metricDuration(report.previous.summary.observed)} previous / {metricDuration(
report.summary.observed
)} current. Percentage points show the difference between two percentages. Equal windows do
not guarantee equal observation coverage.
)}. Average lobbies running: {report.previous.running.average === null
? '—'
: metricNumber(report.previous.running.average)} previous /
{report.running.average === null ? '—' : metricNumber(report.running.average)} current. Captured
wall time: {metricDuration(report.previous.running.capturedHours)} previous /
{metricDuration(report.running.capturedHours)} current. Equal windows do not guarantee equal
observation coverage.
</p>
<p>
Time with players is occupied server time divided by known server time. Known time
includes occupied and idle observations; unknown status and collection gaps are excluded
from that percentage.
Lobbies running averages the concurrent lobby count over captured wall time and includes
lobbies with unknown status. Peak is the largest captured concurrent count. Empty spare
share divides lobby time with zero reported players by all captured lobby-hours,
including unknown status. Empty spares are expected when an autoscaling policy keeps
lobbies ready.
</p>
<p>
No empty lobby measures map time when at least one lobby has known occupancy and no
tracked lobby reports zero players. If every lobby is unknown, map availability is
unknown and excluded from the percentage. Player limits are not required. This
availability signal does not establish failed joins or unmet demand. Autoscaling signals
compare observations with the current policy; historical policy settings are not
recorded.
</p>
<p>
Each periodic observation covers at most {ONLINE_MAX_MS / 1000} seconds. Longer collection
@@ -384,8 +397,10 @@
'_',
' '
)}. Daily buckets are 24-hour periods, not local calendar days. The first and latest
buckets can be partial. Percentage bars divide occupied, idle, and unknown time by
captured time; the headline occupancy percentage uses known time only.
buckets can be partial. Average bars divide occupied, empty spare, and unknown
lobby-hours by captured wall time within each bucket, so a partial period is not a lower
lobby count merely because it is shorter. Percentage bars use all captured lobby time.
Instance time with players uses known lobby time only.
</p>
<p>
Historical server rows are grouped by name and may include multiple registrations using