Initial curated ServiceMap source from 7a0a61232d05ba9097432abef6f7f4102a64d0b8
This commit is contained in:
commit
105251b9c8
96 files changed
+23587
No files matched your search
@@ -0,0 +1,134 @@
|
||||
"""Health-evidence selection policy.
|
||||
|
||||
The policy is deliberately small and pure. Storage retains every provider
|
||||
claim; this module decides which *current component-scoped* claim can answer
|
||||
the direct-health question. It keeps aggregate AppOps health useful in the
|
||||
inspector without ever treating it as a component probe.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
from .models import (
|
||||
EvidenceFreshness,
|
||||
EvidenceProvider,
|
||||
EvidenceScope,
|
||||
HealthEvidence,
|
||||
HealthResolution,
|
||||
HealthResolutionReason,
|
||||
HealthStatus,
|
||||
)
|
||||
|
||||
_PROVIDER_PRIORITY = {
|
||||
EvidenceProvider.MANUAL: 100,
|
||||
EvidenceProvider.PROBE: 90,
|
||||
EvidenceProvider.DOCKER: 80,
|
||||
EvidenceProvider.APPOPS: 40,
|
||||
EvidenceProvider.RUNTIME: 20,
|
||||
}
|
||||
|
||||
|
||||
def appops_health_status(value: str | None) -> HealthStatus | None:
|
||||
"""Keep AppOps aggregate health scoped to the application it describes."""
|
||||
|
||||
return {
|
||||
"unhealthy": HealthStatus.DOWN,
|
||||
"down": HealthStatus.DOWN,
|
||||
"warning": HealthStatus.DEGRADED,
|
||||
"degraded": HealthStatus.DEGRADED,
|
||||
"healthy": HealthStatus.HEALTHY,
|
||||
}.get((value or "").casefold())
|
||||
|
||||
|
||||
def utc_now() -> datetime:
|
||||
return datetime.now(UTC)
|
||||
|
||||
|
||||
def freshness_for(evidence: HealthEvidence, *, now: datetime | None = None) -> EvidenceFreshness:
|
||||
"""Return freshness without mutating the persisted observation.
|
||||
|
||||
The bounded stale window is solely explanatory: stale and expired claims
|
||||
are both excluded from health selection. Showing the distinction helps an
|
||||
operator understand whether a provider is merely late or genuinely old.
|
||||
"""
|
||||
|
||||
now = now or utc_now()
|
||||
if evidence.valid_until >= now:
|
||||
return EvidenceFreshness.FRESH
|
||||
ttl = max(evidence.valid_until - evidence.observed_at, timedelta(seconds=1))
|
||||
return (
|
||||
EvidenceFreshness.STALE if evidence.valid_until + ttl >= now else EvidenceFreshness.EXPIRED
|
||||
)
|
||||
|
||||
|
||||
def with_freshness(evidence: HealthEvidence, *, now: datetime | None = None) -> HealthEvidence:
|
||||
return evidence.model_copy(update={"freshness": freshness_for(evidence, now=now)})
|
||||
|
||||
|
||||
def resolve_health(
|
||||
evidence: list[HealthEvidence], *, now: datetime | None = None
|
||||
) -> HealthResolution:
|
||||
"""Resolve current direct health from independently persisted evidence."""
|
||||
|
||||
now = now or utc_now()
|
||||
annotated = [with_freshness(item, now=now) for item in evidence]
|
||||
eligible = [
|
||||
item
|
||||
for item in annotated
|
||||
if item.active
|
||||
and item.scope == EvidenceScope.COMPONENT
|
||||
and item.freshness == EvidenceFreshness.FRESH
|
||||
]
|
||||
if not eligible:
|
||||
component_claims = [
|
||||
item for item in annotated if item.scope == EvidenceScope.COMPONENT and item.active
|
||||
]
|
||||
app_claims = [
|
||||
item for item in annotated if item.scope == EvidenceScope.APPLICATION and item.active
|
||||
]
|
||||
if component_claims:
|
||||
reason_code = (
|
||||
HealthResolutionReason.STALE_EVIDENCE
|
||||
if any(item.freshness == EvidenceFreshness.STALE for item in component_claims)
|
||||
else HealthResolutionReason.EXPIRED_EVIDENCE
|
||||
)
|
||||
elif app_claims:
|
||||
reason_code = HealthResolutionReason.APPLICATION_SCOPED_ONLY
|
||||
else:
|
||||
reason_code = HealthResolutionReason.NO_CURRENT_COMPONENT_EVIDENCE
|
||||
explanation = (
|
||||
"Only application-scoped evidence is current; it is shown for provenance and is not "
|
||||
"used as component health."
|
||||
if app_claims
|
||||
else "No current component-scoped health evidence is available."
|
||||
)
|
||||
return HealthResolution(reason_code=reason_code, explanation=explanation, evidence=annotated)
|
||||
|
||||
ordered = sorted(
|
||||
eligible,
|
||||
key=lambda item: (
|
||||
_PROVIDER_PRIORITY[item.provider],
|
||||
item.confidence,
|
||||
item.observed_at,
|
||||
item.received_at,
|
||||
item.id,
|
||||
),
|
||||
reverse=True,
|
||||
)
|
||||
selected = ordered[0]
|
||||
conflict = len({item.status for item in eligible}) > 1
|
||||
scope_note = " Conflicting current component signals are retained below." if conflict else ""
|
||||
return HealthResolution(
|
||||
status=selected.status,
|
||||
selected_evidence_id=selected.id,
|
||||
selected_provider=selected.provider,
|
||||
confidence=selected.confidence,
|
||||
reason_code=HealthResolutionReason.SELECTED_COMPONENT_EVIDENCE,
|
||||
explanation=(
|
||||
f"{selected.provider.value} selected from current component-scoped evidence "
|
||||
f"(confidence {selected.confidence:.2f}).{scope_note}"
|
||||
),
|
||||
conflict=conflict,
|
||||
evidence=annotated,
|
||||
)
|
||||
Reference in new issue
Block a user