Skip to content

Commit 9fd41f8

Browse files
committed
CMR-11195: remove /health caching, updates readme
1 parent 2fef479 commit 9fd41f8

3 files changed

Lines changed: 7 additions & 46 deletions

File tree

search-proxy/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Always returns HTTP 200. Used for ALB/ECS target group health checks so that Red
8989

9090
### `GET /health`
9191

92-
Informational health check. Always returns HTTP 200dependencies report their status but do not affect the top-level `ok?`. The result is cached for 5 seconds (unhealthy results are not cached so recovery is visible immediately).
92+
Informational health check, not cached. Nothing automated polls it — ALB/ECS use `/health/shallow`. Currently always returns HTTP 200: dependencies report their status but do not affect the top-level `ok?`.
9393

9494
```json
9595
{

search-proxy/src/proxy/app.py

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,6 @@ async def forward_to_backend(
212212
return response
213213

214214

215-
# Cached health check result with TTL-based expiration
216-
_health_cache: dict = {"result": None, "expires": 0.0}
217-
_HEALTH_CACHE_TTL = 5.0
218-
219-
220215
@app.get("/health/shallow")
221216
async def health_shallow():
222217
return JSONResponse(status_code=200, content={"ok?": True})
@@ -226,19 +221,9 @@ async def health_shallow():
226221
async def health(request: Request):
227222
"""Health check matching CMR's {:ok? bool :dependencies {...}} format.
228223
229-
Each dependency reports ok? and optionally a problem string. Lane
230-
status is included so the health endpoint doubles as the single
231-
place to check lane utilization."""
232-
now = time.monotonic()
233-
234-
# Return cached result if still valid
235-
if _health_cache["result"] and now < _health_cache["expires"]:
236-
cached = _health_cache["result"]
237-
return JSONResponse(
238-
status_code=cached["status_code"],
239-
content=cached["content"],
240-
)
241-
224+
Informational only and not cached — nothing automated polls this
225+
(ALB/ECS use /health/shallow). It exists so an operator can see
226+
dependency and lane-utilization status in one place."""
242227
dependencies = {}
243228

244229
# Redis
@@ -286,12 +271,6 @@ async def health(request: Request):
286271
status_code = 200 if ok else 503
287272
content = {"ok?": ok, "dependencies": dependencies}
288273

289-
# Only cache healthy results so recovery is visible on the next check.
290-
# Use monotonic time (consistent with the check at the top of this function).
291-
if status_code == 200:
292-
_health_cache["result"] = {"status_code": status_code, "content": content}
293-
_health_cache["expires"] = now + _HEALTH_CACHE_TTL
294-
295274
return JSONResponse(status_code=status_code, content=content)
296275

297276

search-proxy/test/test_app.py

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import httpx
88
import pytest
99

10-
from proxy.app import DEFAULT_TOGGLES, _health_cache, app, filter_hop_headers
10+
from proxy.app import DEFAULT_TOGGLES, app, filter_hop_headers
1111
from proxy.cache import ResponseCache
1212
from proxy.config import LaneConfig, LanesConfig, ProxySettings
1313
from proxy.lanes import RequestLanes
@@ -80,9 +80,6 @@ async def client():
8080
app.state.backend.get = AsyncMock(return_value=make_backend_response())
8181
app.state.backend.request = AsyncMock(return_value=make_backend_response())
8282

83-
_health_cache["result"] = None
84-
_health_cache["expires"] = 0.0
85-
8683
async with httpx.AsyncClient(
8784
transport=httpx.ASGITransport(app=app),
8885
base_url="http://test",
@@ -131,8 +128,6 @@ async def test_health_reports_lane_at_capacity(self, client):
131128
fake_redis = app.state.redis
132129
future = time.time() + 300
133130
await fake_redis.zadd("lane:heavy:active", {f"req-{i}": future for i in range(50)})
134-
_health_cache["result"] = None
135-
_health_cache["expires"] = 0.0
136131
resp = await client.get("/health")
137132
data = resp.json()
138133
assert resp.status_code == 200
@@ -146,23 +141,10 @@ async def test_health_shallow_always_200(self, client):
146141
assert resp.status_code == 200
147142
assert resp.json()["ok?"] is True
148143

149-
async def test_health_caches_result(self, client):
150-
"""Rapid /health calls should hit the cache, not backend each time."""
151-
app.state.backend.get.return_value = make_backend_response()
152-
await client.get("/health")
153-
await client.get("/health")
154-
health_calls = [
155-
c
156-
for c in app.state.backend.get.call_args_list
157-
if "/search/health" in str(c)
158-
]
159-
assert len(health_calls) == 1
160-
161-
async def test_health_cache_expires(self, client):
162-
"""After TTL expires, /health should re-check the backend."""
144+
async def test_health_not_cached(self, client):
145+
"""/health is not cached — every call re-checks the backend."""
163146
app.state.backend.get.return_value = make_backend_response()
164147
await client.get("/health")
165-
_health_cache["expires"] = 0.0
166148
await client.get("/health")
167149
health_calls = [
168150
c

0 commit comments

Comments
 (0)