2.5 KiB
Service contract and architecture
Resource
A monitor has UUID id, name, absolute HTTP(S) url, timestamps, and current_status. Status is initially unknown; an HTTP 200–399 result is up, any other HTTP response is down, and timeout/network/security failures set error. Status records include check time and latency; successful HTTP exchanges also include the status code. Secrets or response bodies are never retained.
HTTP API
| Method/path | Result |
|---|---|
POST /monitors |
Create, 201 |
GET /monitors |
List, 200 |
GET /monitors/{id} |
Read, 200 |
PUT /monitors/{id} |
Replace name/url, 200; resets status if URL changes |
DELETE /monitors/{id} |
Delete, 204 |
POST /monitors/{id}/check |
Check now and atomically update status, 200 |
GET /monitors/{id}/status |
Current status, 200 |
GET /healthz |
Liveness, 200 |
GET /readyz |
Readiness, 200 after state/checker initialization |
Unknown resources return 404. Invalid requests return 422. Capacity returns 409. Unsafe targets return 400, outbound network failures 502, and timeout 504. Errors use {"error":{"code":"...","message":"..."}}. No authentication is provided; deploy behind an authenticated trusted gateway if exposed.
Check security
Only HTTP(S), host-bearing URLs without userinfo are accepted. A dedicated resolver rejects every non-global address from every DNS answer. Redirects are followed manually, resolved relative to the previous URL, and revalidated before each hop. The production aiohttp connector uses that same resolver, disables DNS caching, and closes connections, so connection resolution cannot bypass filtering. Total timeout and redirect count are bounded. The service does not return response bodies.
Concurrency and lifecycle
MonitorStore owns one dictionary guarded by an asyncio.Lock. Mutations and status publication are atomic. Status publication uses the checked URL as a compare condition: a concurrent URL change cannot publish a stale result and produces a 409. Memory is per process, starts empty, and disappears on restart. A one-worker deployment is required unless the store is replaced.
Logging and structure
Application events are single-line JSON. Logged URLs are transformed to scheme/host/path only; credentials, query, and fragment are removed. Error text from remote systems is not logged. main owns routing/lifespan, store owns state, checker owns outbound security, models owns wire types, config owns environment validation, and logging_config owns JSON/redaction behavior.