Skip to content

Commit 2fb510d

Browse files
committed
fix: converge changing topic shards
1 parent 03e347f commit 2fb510d

2 files changed

Lines changed: 39 additions & 16 deletions

File tree

scripts/sync_topic_plugins.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -272,23 +272,26 @@ def search_page(self, query_text: str, page: int) -> dict[str, Any]:
272272
return payload
273273

274274
def collect_query(self, query_text: str, first: dict[str, Any]) -> list[dict[str, Any]]:
275-
total = int(first.get("total_count", 0))
276-
if total > 1000:
275+
initial_total = int(first.get("total_count", 0))
276+
if initial_total > 1000:
277277
raise SyncError(f"search shard still exceeds 1,000 repositories: {query_text}")
278-
repositories = list(first.get("items", []))
279-
page = 2
280-
while len(repositories) < total:
281-
payload = self.search_page(query_text, page)
282-
items = payload.get("items", [])
283-
if not items:
284-
break
285-
repositories.extend(items)
286-
page += 1
287-
if len(repositories) != total:
288-
raise SyncError(
289-
f"search shard reported {total} repositories but returned {len(repositories)}"
290-
)
291-
return repositories
278+
seen: dict[int, dict[str, Any]] = {}
279+
next_first = first
280+
for _ in range(3):
281+
latest_total = int(next_first.get("total_count", 0))
282+
page = 1
283+
while page <= max(1, (latest_total + 99) // 100):
284+
payload = next_first if page == 1 else self.search_page(query_text, page)
285+
latest_total = int(payload.get("total_count", latest_total))
286+
for item in payload.get("items", []):
287+
seen[int(item["id"])] = item
288+
page += 1
289+
if len(seen) >= latest_total:
290+
return list(seen.values())
291+
next_first = self.search_page(query_text, 1)
292+
raise SyncError(
293+
f"search shard did not converge: latest={latest_total}, unique={len(seen)}"
294+
)
292295

293296
def collect_date_range(
294297
self,

tests/test_topic_sync.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,26 @@ def test_deferred_candidate_is_not_publishable(self):
141141
self.assertFalse(candidate["enriched"])
142142
self.assertEqual(candidate["reasons"], ["enrichment_deferred"])
143143

144+
def test_search_shard_converges_when_topic_grows_during_pagination(self):
145+
class GrowingClient(topic_sync.GitHubClient):
146+
def __init__(self):
147+
pass
148+
149+
def search_page(self, query_text, page):
150+
if page == 2:
151+
return {
152+
"total_count": 104,
153+
"items": [{"id": value} for value in range(101, 105)],
154+
}
155+
raise AssertionError("unexpected page")
156+
157+
first = {
158+
"total_count": 102,
159+
"items": [{"id": value} for value in range(1, 101)],
160+
}
161+
items = GrowingClient().collect_query("topic:dsh-plugin", first)
162+
self.assertEqual(len(items), 104)
163+
144164
def test_changelog_and_report_are_idempotent(self):
145165
promoted = [
146166
{

0 commit comments

Comments
 (0)