Spaces:
Running
perf(feed): fetch candidate vectors and details side by side
Browse filesThe multi-interest build fetched its candidates' vectors (Qdrant, in
Europe) and then their details (the sidecar, else Turso, in Mumbai), one
after the other, though neither needs the other. They now run together
and the build waits for the slower one. The feed is unchanged: a test
checks the same ranked list and tags whichever fetch finishes first.
Measured 2026-10-23 from a laptop in India against the live services,
12 saves in 3 interests, four fresh processes each: vectors about
0.85 s, details 0.2-0.47 s, build 1.9-2.2 s either way; side by side
the vector fetch slowed under contention, so the saving there was small
and noisy. The Space is the case that matters: its own probe takes
978 ms for SELECT 1 to Turso (112 ms from the laptop), so there the
details are likely the long half. feed_tier1 now reports both halves
(cand_vectors_ms, cand_details_ms) next to their wall time
(candidate_meta_ms), so the saving can be read off production.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@@ -948,12 +948,24 @@ async def _multi_interest_recommend(
|
|
| 948 |
# get_paper_vectors is now LRU-cached by arxiv_id (qdrant_svc),
|
| 949 |
# so warm cache makes this cheap; only fresh papers pay the
|
| 950 |
# disk-read cost.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 951 |
t0_cand_meta = time.time()
|
| 952 |
-
|
| 953 |
-
|
| 954 |
-
|
| 955 |
-
|
| 956 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 957 |
cand_missing = [cid for cid in candidate_ids if cid not in cand_meta]
|
| 958 |
if cand_missing:
|
| 959 |
try:
|
|
|
|
| 948 |
# get_paper_vectors is now LRU-cached by arxiv_id (qdrant_svc),
|
| 949 |
# so warm cache makes this cheap; only fresh papers pay the
|
| 950 |
# disk-read cost.
|
| 951 |
+
#
|
| 952 |
+
# The two fetches need nothing from each other (vectors from Qdrant,
|
| 953 |
+
# details from the sidecar or Turso), so they run side by side and the
|
| 954 |
+
# build waits for the slower one, not both. Measured 2026-10-23 against
|
| 955 |
+
# the live services, 12 saves in 3 interests: 0.85 s and 0.2-0.47 s.
|
| 956 |
t0_cand_meta = time.time()
|
| 957 |
+
|
| 958 |
+
async def _timed(key: str, coro):
|
| 959 |
+
t0 = time.time()
|
| 960 |
+
try:
|
| 961 |
+
return await coro
|
| 962 |
+
finally:
|
| 963 |
+
timing[key] = int((time.time() - t0) * 1000)
|
| 964 |
+
|
| 965 |
+
cand_vectors, cand_meta = await asyncio.gather(
|
| 966 |
+
_timed("cand_vectors_ms", qdrant_svc.get_paper_vectors(candidate_ids)),
|
| 967 |
+
_timed("cand_details_ms", turso_svc.fetch_metadata_batch(candidate_ids)),
|
| 968 |
+
)
|
| 969 |
cand_missing = [cid for cid in candidate_ids if cid not in cand_meta]
|
| 970 |
if cand_missing:
|
| 971 |
try:
|
|
@@ -99,3 +99,20 @@ async def test_a_served_page_records_what_the_reader_waited_for(monkeypatch):
|
|
| 99 |
stats = runtime_stats.timings()
|
| 100 |
assert {"page_ms", "log_ms", "cards_ms", "request_ms"} <= stats["feed_first_page"].keys()
|
| 101 |
assert "request_ms" in stats["feed_next_page"] and "total_ms" in stats["feed_tier1"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
stats = runtime_stats.timings()
|
| 100 |
assert {"page_ms", "log_ms", "cards_ms", "request_ms"} <= stats["feed_first_page"].keys()
|
| 101 |
assert "request_ms" in stats["feed_next_page"] and "total_ms" in stats["feed_tier1"]
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
async def test_candidate_vectors_and_details_are_fetched_side_by_side(monkeypatch):
|
| 105 |
+
install(monkeypatch, vectors_wait=0.3, details_wait=0.3)
|
| 106 |
+
state = await reader()
|
| 107 |
+
*_, timing = await recs._multi_interest_recommend(READER, state, set(), 60, query_id="q")
|
| 108 |
+
assert timing["cand_vectors_ms"] >= 300 and timing["cand_details_ms"] >= 300
|
| 109 |
+
assert timing["candidate_meta_ms"] < 500 # one wait, not two
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
async def test_which_fetch_finishes_first_does_not_change_the_feed(monkeypatch):
|
| 113 |
+
install(monkeypatch, vectors_wait=0.15)
|
| 114 |
+
state = await reader()
|
| 115 |
+
vectors_last = await recs._multi_interest_recommend(READER, state, set(), 60, query_id="q")
|
| 116 |
+
install(monkeypatch, details_wait=0.15)
|
| 117 |
+
details_last = await recs._multi_interest_recommend(READER, state, set(), 60, query_id="q")
|
| 118 |
+
assert vectors_last[0] == details_last[0] and vectors_last[2] == details_last[2]
|