Source code for fluxlit.health
"""Readiness probes for the unified runtime (Streamlit sidecar)."""
from __future__ import annotations
from urllib.parse import urlparse
import httpx
from fluxlit.config import FluxlitSettings
from fluxlit.runtime import read_streamlit_upstream_url
def _streamlit_readiness_urls(
upstream: str, *, settings: FluxlitSettings | None = None
) -> list[str]:
"""Candidate Streamlit URLs that indicate the sidecar is serving traffic."""
base = upstream.rstrip("/")
urls = [f"{base}/"]
mount = (settings or FluxlitSettings()).public_mount_path().strip().strip("/")
if mount:
urls.append(f"{base}/{mount}/")
return urls
[docs]
async def probe_streamlit_ready(
*,
timeout_s: float = 0.5,
upstream: str | None = None,
settings: FluxlitSettings | None = None,
) -> tuple[bool, str]:
"""Return ``(ok, detail)`` for whether the Streamlit upstream accepts HTTP traffic.
When ``FLUXLIT_STREAMLIT_UPSTREAM`` / file state is unset (typical in bare FastAPI
tests), returns ``(True, "not_configured")``.
When configured, readiness requires an HTTP **2xx** response from ``GET`` on at least
one candidate URL (see :func:`_streamlit_readiness_urls`). Other status codes are treated
as not ready. When multiple URLs are probed and all fail, ``detail`` aggregates path and
status (for example ``upstream_http_failed /:404;/myapp/:503``).
"""
resolved_upstream = read_streamlit_upstream_url() if upstream is None else upstream
if not resolved_upstream:
return True, "not_configured"
try:
async with httpx.AsyncClient(timeout=timeout_s) as client:
failures: list[str] = []
for url in _streamlit_readiness_urls(resolved_upstream, settings=settings):
response = await client.get(url)
if 200 <= response.status_code < 300:
return True, "ok"
path = urlparse(url).path or "/"
failures.append(f"{path}:{response.status_code}")
joined = ";".join(failures)
return False, f"upstream_http_failed {joined}"
except (httpx.HTTPError, OSError) as e:
# Some Win32 socket errors stringify to "", but tests/ops want a non-empty reason.
detail = str(e) or f"{type(e).__name__}: {e!r}"
return False, detail