Files
ServiceMap-Public/backend/app/demo.py
T

122 lines
6.0 KiB
Python

from __future__ import annotations
from datetime import UTC, datetime, timedelta
from uuid import UUID, uuid5
from .models import (
ComponentRole,
Criticality,
DiscoveryCategory,
HealthStatus,
ProbeResult,
Service,
ServiceKind,
)
DEMO_SCENARIO_NAME = "Northstar Platform"
DEMO_ROOT_CAUSE_NAME = "PostgreSQL"
_DEMO_NAMESPACE = UUID("4b3f31f4-8ee8-4e34-9a30-4bd4e5d4d4c1")
def _stable_id(label: str) -> str:
return str(uuid5(_DEMO_NAMESPACE, label))
def build_demo_records(now: datetime | None = None) -> tuple[list[Service], list[ProbeResult]]:
"""Build the complete deterministic Northstar topology and its synthetic history."""
current = now or datetime.now(UTC)
definitions = [
("Public Endpoint", ServiceKind.HTTP, "https://northstar.synthetic/public", None, None, ["Reverse Proxy"]),
("Reverse Proxy", ServiceKind.HTTP, "https://northstar.synthetic/proxy", None, None, ["Web Frontend", "Auth Service"]),
("Web Frontend", ServiceKind.HTTP, "https://northstar.synthetic/web", None, None, ["API Gateway"]),
("Auth Service", ServiceKind.HTTP, "https://northstar.synthetic/auth", None, None, []),
("API Gateway", ServiceKind.HTTP, "https://northstar.synthetic/api", None, None, ["PostgreSQL", "Redis"]),
("PostgreSQL", ServiceKind.TCP, None, "postgresql.northstar.synthetic", 5432, []),
("Redis", ServiceKind.TCP, None, "redis.northstar.synthetic", 6379, []),
("Background Worker", ServiceKind.TCP, None, "worker.northstar.synthetic", 9000, ["PostgreSQL", "Redis", "Object Storage"]),
("Object Storage", ServiceKind.HTTP, "https://northstar.synthetic/object-storage", None, None, []),
]
ids_by_name = {name: _stable_id(f"service:{name}") for name, *_ in definitions}
metadata = {
"Public Endpoint": ("Edge", "Public Gateway", "Edge", ComponentRole.FRONTEND, DiscoveryCategory.PROXY, Criticality.CRITICAL, "Customer-facing availability check", 100.0),
"Reverse Proxy": ("Edge", "Public Gateway", "Edge", ComponentRole.PROXY, DiscoveryCategory.PROXY, Criticality.HIGH, "Northstar ingress gateway", 100.0),
"Web Frontend": ("Application", "Northstar App", "Application", ComponentRole.FRONTEND, DiscoveryCategory.APPLICATION, Criticality.HIGH, "Browser application", 99.0),
"Auth Service": ("Application", "Northstar App", "Application", ComponentRole.API, DiscoveryCategory.APPLICATION, Criticality.HIGH, "Identity and session service", 100.0),
"API Gateway": ("Application", "Northstar App", "Application", ComponentRole.API, DiscoveryCategory.APPLICATION, Criticality.CRITICAL, "Application API entry point", 99.0),
"PostgreSQL": ("Data", "Data Platform", "Data", ComponentRole.DATABASE, DiscoveryCategory.DATABASE, Criticality.CRITICAL, "Primary relational datastore", 99.9),
"Redis": ("Data", "Data Platform", "Data", ComponentRole.CACHE, DiscoveryCategory.CACHE, Criticality.HIGH, "Cache and queue backend", 100.0),
"Background Worker": ("Application", "Worker Platform", "Application", ComponentRole.WORKER, DiscoveryCategory.BACKGROUND_WORKER, Criticality.HIGH, "Asynchronous job processor", 99.0),
"Object Storage": ("Data", "Worker Platform", "Application", ComponentRole.STORAGE, DiscoveryCategory.STORAGE, Criticality.MEDIUM, "Durable object store", 100.0),
}
services = [
Service(
id=ids_by_name[name],
name=name,
kind=kind,
url=url,
host=host,
port=port,
depends_on=[ids_by_name[item] for item in dependencies],
group=metadata[name][0],
environment="production",
application=metadata[name][1],
domain=metadata[name][2],
component_role=metadata[name][3],
category=metadata[name][4],
criticality=metadata[name][5],
description=metadata[name][6],
availability_target=metadata[name][7],
interval_seconds=60,
created_at=current - timedelta(days=30),
updated_at=current,
)
for name, kind, url, host, port, dependencies in definitions
]
probes: list[ProbeResult] = []
for name, *_ in definitions:
for index in range(24):
status = _history_status(name, index)
checked_at = current - timedelta(hours=23 - index)
latency = None if status == HealthStatus.DOWN else round(42 + ((index * 17 + len(name) * 3) % 120), 2)
detail = _probe_detail(name, status, index)
probes.append(
ProbeResult(
id=_stable_id(f"probe:{name}:{index}"),
service_id=ids_by_name[name],
status=status,
latency_ms=latency,
detail=detail,
checked_at=checked_at,
trigger="synthetic",
metadata={"scenario": DEMO_SCENARIO_NAME},
)
)
return services, probes
def _history_status(name: str, index: int) -> HealthStatus:
if name == "PostgreSQL":
if index in {21, 23}:
return HealthStatus.DOWN
if index == 22:
return HealthStatus.DEGRADED
if name in {"API Gateway", "Background Worker"} and index == 20:
return HealthStatus.DOWN
if name == "Web Frontend" and index == 21:
return HealthStatus.DOWN
if name == "Reverse Proxy" and index == 22:
return HealthStatus.DEGRADED
return HealthStatus.HEALTHY
def _probe_detail(name: str, status: HealthStatus, index: int) -> str:
if name == DEMO_ROOT_CAUSE_NAME and status == HealthStatus.DOWN:
return "Synthetic outage: PostgreSQL connection refused"
if status == HealthStatus.DOWN:
return f"Synthetic dependency impact observed at history point {index + 1}"
if status == HealthStatus.DEGRADED:
return f"Synthetic elevated latency observed at history point {index + 1}"
return "Synthetic monitoring observation"