Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions src/components/GatewayHealth/GatewayTimeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import styles from './timeline.module.css';

// Gateway Health: MCP Gateway and LLM Gateway sections, both fetched from rollup_server.py, which lives in the
// macrodata-refinement repo at OTHER_APPS/gateway_health/rollup_server.py (this repo has no backend).
// Bucket = { t, state: 'operational'|'degraded'|'partial'|'major'|'maintenance'|'nodata', p95, errorRate, requests, incidentId }
// Bucket = { t, state: 'operational'|'degraded'|'partial'|'major'|'monitor_disconnected'|'maintenance'|'nodata', p95, errorRate, requests, incidentId }
// monitor_disconnected = the sustained failures behind this bucket never got a response at all
// (the monitoring worker/host itself lost outbound connectivity), not the real gateway
// infrastructure failing - see is_connectivity_error in rollup_server.py.

/* ────────────────────────────────── Config ─────────────────────────── */

Expand All @@ -17,13 +20,15 @@ const STATE_META = {
degraded: { label: 'Degraded' },
partial: { label: 'Partial outage' },
major: { label: 'Major outage' },
monitor_disconnected: { label: 'Monitoring interrupted' },
maintenance: { label: 'Maintenance' },
nodata: { label: 'No data' },
};

// How much each hour counts against uptime (maintenance is excluded entirely).
const DOWN_WEIGHT = { operational: 0, degraded: 0, partial: 0.5, major: 1, maintenance: 0, nodata: 0 };
const SEVERITY_RANK = { operational: 0, maintenance: 1, degraded: 2, partial: 3, major: 4, nodata: 0 };
// How much each hour counts against uptime (maintenance and monitor_disconnected are excluded
// entirely - neither reflects the real gateway's health, just a monitoring gap).
const DOWN_WEIGHT = { operational: 0, degraded: 0, partial: 0.5, major: 1, monitor_disconnected: 0, maintenance: 0, nodata: 0 };
const SEVERITY_RANK = { operational: 0, maintenance: 1, monitor_disconnected: 1, degraded: 2, partial: 3, major: 4, nodata: 0 };

const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

Expand All @@ -35,7 +40,7 @@ function summarize(buckets) {
let errSum = 0;
let reqTotal = 0;
for (const b of buckets) {
if (b.state !== 'maintenance') {
if (b.state !== 'maintenance' && b.state !== 'monitor_disconnected') {
denom += 1;
downWeight += DOWN_WEIGHT[b.state];
}
Expand Down Expand Up @@ -250,6 +255,8 @@ export default function GatewayTimeline() {
const label =
worst === 'operational' || worst === 'maintenance'
? 'All Systems Operational'
: worst === 'monitor_disconnected'
? 'Monitoring Interrupted'
: worst === 'degraded'
? 'Degraded Performance'
: worst === 'partial'
Expand Down Expand Up @@ -325,7 +332,7 @@ export default function GatewayTimeline() {
{renderGroup('LLM Gateway', llmRows)}

<div className={styles.legend}>
{['operational', 'degraded', 'partial', 'major', 'maintenance'].map((s) => (
{['operational', 'degraded', 'partial', 'major', 'monitor_disconnected', 'maintenance'].map((s) => (
<span key={s} className={styles.legendItem}>
<span className={`${styles.swatch} ${styles[`s_${s}`]}`} />
{STATE_META[s].label}
Expand Down
8 changes: 8 additions & 0 deletions src/components/GatewayHealth/timeline.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@
background: rgba(37, 99, 235, 0.1);
border-color: rgba(37, 99, 235, 0.3);
}
.p_monitor_disconnected {
color: #6d28d9;
background: rgba(124, 58, 237, 0.1);
border-color: rgba(124, 58, 237, 0.3);
}
.p_nodata {
color: var(--ifm-color-content-secondary);
background: var(--docs-light-surface-raised);
Expand All @@ -120,6 +125,7 @@
:global([data-theme='dark']) .p_partial { color: #fdba74; }
:global([data-theme='dark']) .p_major { color: #fca5a5; }
:global([data-theme='dark']) .p_maintenance { color: #93c5fd; }
:global([data-theme='dark']) .p_monitor_disconnected { color: #c4b5fd; }
:global([data-theme='dark']) .p_nodata {
background: var(--docs-dark-surface-raised);
border-color: var(--docs-dark-border);
Expand Down Expand Up @@ -323,13 +329,15 @@
.s_partial { background: rgba(234, 88, 12, 0.9); }
.s_major { background: rgba(220, 38, 38, 0.92); }
.s_maintenance { background: rgba(37, 99, 235, 0.65); }
.s_monitor_disconnected { background: rgba(124, 58, 237, 0.65); }
.s_nodata { background: var(--docs-light-border-strong); }

:global([data-theme='dark']) .s_operational { background: rgba(52, 211, 153, 0.5); }
:global([data-theme='dark']) .s_degraded { background: rgba(251, 191, 36, 0.8); }
:global([data-theme='dark']) .s_partial { background: rgba(251, 146, 60, 0.85); }
:global([data-theme='dark']) .s_major { background: rgba(248, 113, 113, 0.9); }
:global([data-theme='dark']) .s_maintenance { background: rgba(96, 165, 250, 0.7); }
:global([data-theme='dark']) .s_monitor_disconnected { background: rgba(167, 139, 250, 0.75); }
:global([data-theme='dark']) .s_nodata { background: var(--docs-dark-border-strong); }

/* ── Legend ──────────────────────────────────────────────────────────── */
Expand Down
Loading