perf: inline cache fast path; cache /health checks
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 23s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Build Docker Image (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Integration Test with Services (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Staging (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Production (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Performance Test (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Code Quality (push) Successful in 12s
Documentation / Validate Documentation (push) Failing after 9s
Documentation / Build Sphinx Documentation (push) Successful in 14s
Documentation / Generate API Documentation (push) Successful in 8s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 0s
Documentation / Documentation Summary (push) Successful in 3s

The on-box load test exposed the real stall: cache HITS were dispatched
through asyncio.to_thread, so under load a microsecond lookup queued
~11s behind slow work in the ~8-thread default executor (endpoints
answered inline — /forecast 4ms, /api/stats 2ms — while every to_thread
endpoint sat at p50 8-17s). Handlers now check TTL caches inline in the
async path via _cache_fresh() and only pay for a thread on a miss.

/health results are cached for HEALTH_CACHE_TTL_SECONDS (10): its
external RID-API probe plus DB query were occupying executor threads on
every hit, which is what jammed the pool in the first place.
This commit is contained in:
2026-08-12 11:48:05 +07:00
parent 1ec5cfb4df
commit d9c65bcf0c
2 changed files with 64 additions and 13 deletions
+3
View File
@@ -91,6 +91,9 @@ class Config:
# TTL for the /measurements/latest response cache (hottest endpoint)
LATEST_CACHE_TTL_SECONDS = int(os.getenv("LATEST_CACHE_TTL_SECONDS", "45"))
# TTL for /health check results (includes an external RID-API probe)
HEALTH_CACHE_TTL_SECONDS = int(os.getenv("HEALTH_CACHE_TTL_SECONDS", "10"))
# Web server worker processes. Above 1, uvicorn forks workers and a
# localhost lock port elects a single background-collection leader.
WEB_WORKERS = int(os.getenv("WEB_WORKERS", "2"))