Fix fleet stale-status flicker during polling
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { parseServerName, zombieMapBySlug } from './map-aliases.js';
|
||||
import { freshStatusTimestamp } from './server-freshness.js';
|
||||
import type { ZombieGame } from './map-aliases.js';
|
||||
import type { RoundTelemetry } from './telemetry.js';
|
||||
import type { Health, RosterPlayer } from './ui/stores/servers.js';
|
||||
@@ -40,8 +41,7 @@ export type FleetFilter = 'all' | 'occupied' | 'empty' | 'attention' | 'testing'
|
||||
export type FleetSort = 'name' | 'players' | 'round' | 'duration';
|
||||
|
||||
export function freshServer(server: FleetServer, now: number): boolean {
|
||||
const age = now - Date.parse(server.last_seen_at ?? '');
|
||||
return server.health === 'online' && age >= 0 && age <= 30_000;
|
||||
return server.health === 'online' && !server.last_error && freshStatusTimestamp(server.last_seen_at, now);
|
||||
}
|
||||
|
||||
export function fleetIdentity(server: FleetServer) {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Allow a polling cycle plus time for queued RCON requests and delivery.
|
||||
export const STATUS_REFRESH_MS = 30_000;
|
||||
export const ONLINE_MAX_MS = STATUS_REFRESH_MS + 15_000;
|
||||
// The UI clock ticks once per second and can trail a newly arrived report.
|
||||
const CLOCK_TOLERANCE_MS = 1_000;
|
||||
|
||||
export function freshStatusTimestamp(timestamp: string | null, now: number): boolean {
|
||||
const age = now - Date.parse(timestamp ?? '');
|
||||
return age >= -CLOCK_TOLERANCE_MS && age <= ONLINE_MAX_MS;
|
||||
}
|
||||
@@ -1,24 +1,24 @@
|
||||
import { freshStatusTimestamp } from '../../server-freshness.js';
|
||||
export type Health = 'online' | 'stale' | 'offline' | 'starting';
|
||||
|
||||
const ONLINE_MAX_MS = 30_000;
|
||||
const STALE_MAX_MS = 120_000;
|
||||
|
||||
/**
|
||||
* Classify server health from its last successful RCON timestamp.
|
||||
* `offline` if we've never seen it, or if RCON just failed, or if the last
|
||||
* successful reply is >120s old. `stale` if the last reply is 30-120s old
|
||||
* (RCON glitchy). `online` if fresh.
|
||||
* `offline` if we've never seen it or the last successful reply is >120s old.
|
||||
* `stale` on an RCON failure or if the last reply is 45-120s old.
|
||||
* `online` if fresh, including the allowance for polling and delivery.
|
||||
*/
|
||||
export function classifyHealth(lastSeenAt: string | null, lastError: string | null, containerState?: string | null): Health {
|
||||
if (containerState === 'starting' || containerState === 'restarting') return 'starting';
|
||||
if (containerState && containerState !== 'running') return 'offline';
|
||||
if (!lastSeenAt) return 'offline';
|
||||
const age = Date.now() - new Date(lastSeenAt).getTime();
|
||||
if (!Number.isFinite(age) || age < 0) return 'offline';
|
||||
if (age <= ONLINE_MAX_MS) {
|
||||
if (freshStatusTimestamp(lastSeenAt, Date.now())) {
|
||||
// Even with a fresh last_seen, a very recent error demotes to stale
|
||||
return lastError ? 'stale' : 'online';
|
||||
}
|
||||
if (!Number.isFinite(age) || age < 0) return 'offline';
|
||||
if (age <= STALE_MAX_MS) return 'stale';
|
||||
return 'offline';
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ import { listServers, setServerField } from '../fleet/servers.js';
|
||||
import { komodoInspectHealthy } from '../integrations/komodo.js';
|
||||
import { restartSettling } from './restart-rollout.js';
|
||||
import { classifyHealth } from '../fleet/health.js';
|
||||
import { STATUS_REFRESH_MS } from '../../server-freshness.js';
|
||||
import { scanMatchState } from '../fleet/match-log.js';
|
||||
|
||||
const TICK_MS = 15_000;
|
||||
const STATUS_REFRESH_MS = 30_000;
|
||||
// Cap concurrent UDP RCON calls so a 15-server fleet doesn't blast the
|
||||
// host all at once.
|
||||
const STATUS_CONCURRENCY = 4;
|
||||
|
||||
Reference in New Issue
Block a user