mirror of
https://github.com/turnstonelabs/turnstone.git
synced 2026-08-12 23:12:23 -06:00
167d63b385
* Add operational features: health degradation, rate limiting, workstream eviction Backend health monitor with circuit breaker (CLOSED/OPEN/HALF_OPEN) probes LLM backend periodically; /health returns "degraded" when unreachable. Token-bucket per-IP rate limiter with 429 + Retry-After responses; /health and /metrics exempt. Workstream auto-eviction of oldest idle when at configurable max_workstreams capacity. New modules: healthcheck.py (BackendHealthMonitor, CircuitState), ratelimit.py (TokenBucket, RateLimiter). 5 new Prometheus metrics. Both UIs: health indicator, 429 retry with toast, eviction notifications, node degradation badges (console), circuit state in dashboard footer. Config: [health] and [ratelimit] TOML sections, max_workstreams in [server]. Docs: README, architecture, API reference, PlantUML diagrams updated. 616 tests pass (35 new), mypy clean, ruff clean. * Fix Copilot PR #10 review: version import, capacity check order, validations, docs - Use turnstone.__version__ instead of hard-coded "0.2.1" in /health and /metrics endpoints - Move capacity check/eviction before session creation in WorkstreamManager.create() to avoid wasted work when at capacity - Validate rate > 0 and burst >= 1 in RateLimiter when enabled - Validate max_workstreams >= 1 in WorkstreamManager.__init__ - Parse do_POST path with urlparse for consistent rate limit exemptions and metrics labeling - Fix should_allow_request docstring: HALF_OPEN allows requests through (not just one probe) - Fix /health docstring: degraded when circuit is not CLOSED (includes HALF_OPEN) - Add class="health-ok" to health indicator HTML to prevent visible empty pill before first poll - Update PlantUML: remove stale MAX_WORKSTREAMS constant, fix RateLimiter.check and TokenBucket signatures; regenerate PNG
35 lines
911 B
Python
35 lines
911 B
Python
#!/usr/bin/env python3
|
|
"""Health check for turnstone containers.
|
|
|
|
Usage: healthcheck.py <url>
|
|
Exit 0 if the endpoint returns {"status": "ok"}, exit 1 otherwise.
|
|
Uses only stdlib — no pip dependencies required.
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
import urllib.request
|
|
|
|
|
|
def main() -> None:
|
|
if len(sys.argv) != 2:
|
|
print("Usage: healthcheck.py <url>", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
url = sys.argv[1]
|
|
try:
|
|
req = urllib.request.Request(url, method="GET")
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
data = json.loads(resp.read().decode())
|
|
if data.get("status") in ("ok", "degraded"):
|
|
sys.exit(0)
|
|
print(f"Unhealthy: {data}", file=sys.stderr)
|
|
sys.exit(1)
|
|
except Exception as exc:
|
|
print(f"Health check failed: {exc}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|