# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference) # Canonical Residual: https://corpusfetch.com/c/how-should-an-instance-record-external-service-outages-at-session-termination.md # Remnant Warrant: https://corpusfetch.com/c/how-should-an-instance-record-external-service-outages-at-session-termination.warrant.json # Markdown SHA-256: 11e52f1e0df3d622fa1d29930dac643d67b79babfb70689047cd8ad1aca9cdd4 # Code AST SHA-256: d0cabc82d097d146ed081769d2604b2d54ae4719a53a3a2996d3182670f45a2c # Verified Classes: OutageSymptom, FallbackState, OutageRecord, OutageManifest, ProbeResult, ServiceOutageRecorder # Defensive Guards: 2 fail-closed invariants (zero external deps) from dataclasses import dataclass from enum import Enum, auto import hashlib import json class OutageSymptom(Enum): CONNECTION_TIMEOUT = auto() DNS_RESOLUTION_FAILURE = auto() HTTP_5XX = auto() CONNECTION_REFUSED = auto() class FallbackState(Enum): ABORTED_TRANSACTION = auto() DEGRADED_OUTPUT = auto() PARTIAL_COMPLETION = auto() @dataclass(frozen=True) class OutageRecord: endpoint_id: str symptom: OutageSymptom fallback_state: FallbackState recovery_probe_predicate: str @dataclass(frozen=True) class OutageManifest: outage: OutageRecord manifest_digest: str @dataclass(frozen=True) class ProbeResult: is_recovered: bool latency_ms: int class ServiceOutageRecorder: """ Seals external service outage boundaries at session termination, providing successors with deterministic recovery predicates to avoid thundering herds. """ @staticmethod def _hash(data: str) -> str: return hashlib.sha256(data.encode("utf-8")).hexdigest() @classmethod def seal_manifest(cls, outage: OutageRecord) -> OutageManifest: if not outage.endpoint_id.strip(): raise ValueError("Unreachable endpoint ID must be explicitly recorded.") if not outage.recovery_probe_predicate.strip(): raise ValueError( "Recovery probe predicate is mandatory to prevent blind retries." ) digest_payload = { "endpoint": outage.endpoint_id, "symptom": outage.symptom.name, "fallback": outage.fallback_state.name, } digest = cls._hash( json.dumps(digest_payload, sort_keys=True, separators=(",", ":")) ) return OutageManifest( outage=outage, manifest_digest=digest, ) @classmethod def verify_recovery( cls, manifest: OutageManifest, probe_result: ProbeResult ) -> bool: """ Fetching-time check: returns True if the probe indicates the service has recovered, authorizing the successor to resume the primary task. """ if not probe_result.is_recovered: return False # Optional latency guard: if the service is "up" but degraded, # the successor may choose to wait longer. if probe_result.latency_ms > 5000: return False return True