Perf: parallelize admin loads + edge-cache /api/brief
Two concrete latency wins found by measuring (server compute is 2-17ms; the time is in the path, not the box): - Admin panel fired its 6 API calls SEQUENTIALLY (await chain) — so it paid the uncached origin round-trip six times back-to-back. Now one Promise.all batch. This is the admin lag. - /api/brief (the home "Gathering the good news…" content) wasn't edge-cached, so a distant anonymous visitor triggered a Cloudflare→residential-origin pull. Same global/shareable boundary as /api/feed: public s-maxage=45 when no prefs/exclude, else private,no-store. (Needs /api/brief added to the CF cache rule path list to take effect at the edge.) Tests: test_brief_cache_boundary. 228 pytest + 11 vitest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -28,12 +28,22 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await loadStats();
|
// Load all panels in PARALLEL — these were sequential awaits, so the page
|
||||||
feedback = await getJSON('/api/admin/feedback');
|
// paid the (uncached, origin) round-trip six times back-to-back. One batch
|
||||||
candidates = await getJSON('/api/admin/candidates');
|
// instead of a chain.
|
||||||
wpPool = await getJSON('/api/admin/word/pool');
|
const [, fb, cand, wp, ce, ws] = await Promise.all([
|
||||||
clientErrors = await getJSON('/api/admin/client-errors');
|
loadStats(),
|
||||||
wsThemes = await getJSON('/api/admin/wordsearch/themes');
|
getJSON('/api/admin/feedback'),
|
||||||
|
getJSON('/api/admin/candidates'),
|
||||||
|
getJSON('/api/admin/word/pool'),
|
||||||
|
getJSON('/api/admin/client-errors'),
|
||||||
|
getJSON('/api/admin/wordsearch/themes'),
|
||||||
|
]);
|
||||||
|
feedback = fb;
|
||||||
|
candidates = cand;
|
||||||
|
wpPool = wp;
|
||||||
|
clientErrors = ce;
|
||||||
|
wsThemes = ws;
|
||||||
} catch {
|
} catch {
|
||||||
error = "Couldn't load stats.";
|
error = "Couldn't load stats.";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1676,11 +1676,17 @@ def create_app() -> FastAPI:
|
|||||||
|
|
||||||
@app.get("/api/brief", response_model=BriefResponse)
|
@app.get("/api/brief", response_model=BriefResponse)
|
||||||
def brief(
|
def brief(
|
||||||
|
response: Response,
|
||||||
date: str | None = Query(None),
|
date: str | None = Query(None),
|
||||||
limit: int = Query(10, ge=1, le=50),
|
limit: int = Query(10, ge=1, le=50),
|
||||||
prefs: str | None = Query(None),
|
prefs: str | None = Query(None),
|
||||||
exclude: str = Query("", description="comma-separated article ids the reader has dismissed"),
|
exclude: str = Query("", description="comma-separated article ids the reader has dismissed"),
|
||||||
) -> BriefResponse:
|
) -> BriefResponse:
|
||||||
|
# The default highlights are global (date-keyed, no session) → edge-cacheable
|
||||||
|
# so a new visitor's "Gathering the good news…" resolves from their POP, not
|
||||||
|
# a pull to the residential origin. Personal filters stay private.
|
||||||
|
shareable = not prefs and not exclude.strip()
|
||||||
|
response.headers["Cache-Control"] = _EDGE_FEED if shareable else _PRIVATE
|
||||||
fp = prefs_from_json(prefs)
|
fp = prefs_from_json(prefs)
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(timezone.utc)
|
||||||
excl = {int(x) for x in exclude.split(",") if x.strip().lstrip("-").isdigit()}
|
excl = {int(x) for x in exclude.split(",") if x.strip().lstrip("-").isdigit()}
|
||||||
|
|||||||
@@ -107,3 +107,10 @@ def test_feed_cache_boundary(client):
|
|||||||
assert client.get("/api/feed", params={"following": "true"}).headers.get("cache-control") == "private, no-store"
|
assert client.get("/api/feed", params={"following": "true"}).headers.get("cache-control") == "private, no-store"
|
||||||
assert client.get("/api/feed", params={"prefs": json.dumps({"mute_topics": ["science"]})}).headers.get("cache-control") == "private, no-store"
|
assert client.get("/api/feed", params={"prefs": json.dumps({"mute_topics": ["science"]})}).headers.get("cache-control") == "private, no-store"
|
||||||
assert client.get("/api/feed", params={"exclude": "1,2"}).headers.get("cache-control") == "private, no-store"
|
assert client.get("/api/feed", params={"exclude": "1,2"}).headers.get("cache-control") == "private, no-store"
|
||||||
|
|
||||||
|
|
||||||
|
def test_brief_cache_boundary(client):
|
||||||
|
# Default highlights are global → public; personal filters → private.
|
||||||
|
assert "public" in client.get("/api/brief").headers.get("cache-control", "")
|
||||||
|
assert client.get("/api/brief", params={"prefs": json.dumps({"mute_topics": ["health"]})}).headers.get("cache-control") == "private, no-store"
|
||||||
|
assert client.get("/api/brief", params={"exclude": "3"}).headers.get("cache-control") == "private, no-store"
|
||||||
|
|||||||
Reference in New Issue
Block a user