Skip to content

Commit 49864f2

Browse files
committed
perf(api): parallelizes main-user backfill with tracked-user searches
1 parent f033e0a commit 49864f2

File tree

1 file changed

+40
-21
lines changed

1 file changed

+40
-21
lines changed

src/app/services/api.ts

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,14 +1400,30 @@ export async function fetchIssuesAndPullRequests(
14001400
});
14011401
}
14021402

1403-
// Tracked user global searches — run in parallel
1404-
if (hasTrackedUsers) {
1405-
const trackedResults = await Promise.allSettled(
1406-
trackedUsers!.map((u) => graphqlGlobalUserSearch(octokit, u.login))
1407-
);
1403+
// Main user node IDs known — start backfill in parallel with tracked user searches.
1404+
// This delivers enriched main-user PRs without waiting for tracked user pagination.
1405+
const mainNodeIds = [...nodeIdMap.values()];
1406+
const mainBackfillPromise = mainNodeIds.length > 0
1407+
? fetchPREnrichment(octokit, mainNodeIds)
1408+
: Promise.resolve({ enrichments: new Map<number, PREnrichmentData>(), errors: [] as ApiError[] });
1409+
1410+
// Tracked user global searches — run in parallel with main backfill
1411+
const trackedSearchPromise = hasTrackedUsers
1412+
? Promise.allSettled(trackedUsers!.map((u) => graphqlGlobalUserSearch(octokit, u.login)))
1413+
: Promise.resolve([] as PromiseSettledResult<LightSearchResult>[]);
1414+
1415+
const [mainBackfill, trackedResults] = await Promise.all([mainBackfillPromise, trackedSearchPromise]);
1416+
1417+
// Merge main backfill results
1418+
const backfillErrors = [...mainBackfill.errors];
1419+
const forkInfoMap = new Map<number, { owner: string; repoName: string }>();
14081420

1409-
for (let i = 0; i < trackedResults.length; i++) {
1410-
const result = trackedResults[i];
1421+
// Merge tracked user results and collect new (delta) node IDs
1422+
const preTrackedPrIds = new Set(prMap.keys());
1423+
if (hasTrackedUsers) {
1424+
const settled = trackedResults as PromiseSettledResult<LightSearchResult>[];
1425+
for (let i = 0; i < settled.length; i++) {
1426+
const result = settled[i];
14111427
const trackedLogin = trackedUsers![i].login;
14121428
if (result.status === "fulfilled") {
14131429
allErrors.push(...result.value.errors);
@@ -1422,22 +1438,25 @@ export async function fetchIssuesAndPullRequests(
14221438
const mergedIssues = [...issueMap.values()];
14231439
const mergedPRs = [...prMap.values()];
14241440

1425-
// Phase 2: heavy backfill — uses union of all node IDs (main + tracked users)
1426-
const allNodeIds = mergedPRs
1427-
.map((pr) => nodeIdMap.get(pr.id))
1428-
.filter((id): id is string => id != null);
1429-
1430-
if (allNodeIds.length === 0) {
1431-
return {
1432-
issues: mergedIssues,
1433-
pullRequests: mergedPRs.map(pr => ({ ...pr, enriched: true })),
1434-
errors: allErrors,
1435-
};
1441+
// Apply main backfill enrichments to all PRs (main user PRs get enriched, tracked-only PRs get nothing yet)
1442+
let enrichedPRs = mainBackfill.enrichments.size > 0
1443+
? mergeEnrichment(mergedPRs, mainBackfill.enrichments, forkInfoMap)
1444+
: mergedPRs;
1445+
1446+
// Delta backfill: enrich only NEW PRs from tracked users (not already in main user's set)
1447+
const deltaNodeIds: string[] = [];
1448+
for (const pr of mergedPRs) {
1449+
if (!preTrackedPrIds.has(pr.id)) {
1450+
const nodeId = nodeIdMap.get(pr.id);
1451+
if (nodeId) deltaNodeIds.push(nodeId);
1452+
}
14361453
}
14371454

1438-
const { enrichments, errors: backfillErrors } = await fetchPREnrichment(octokit, allNodeIds);
1439-
const forkInfoMap = new Map<number, { owner: string; repoName: string }>();
1440-
const enrichedPRs = mergeEnrichment(mergedPRs, enrichments, forkInfoMap);
1455+
if (deltaNodeIds.length > 0) {
1456+
const delta = await fetchPREnrichment(octokit, deltaNodeIds);
1457+
backfillErrors.push(...delta.errors);
1458+
enrichedPRs = mergeEnrichment(enrichedPRs, delta.enrichments, forkInfoMap);
1459+
}
14411460

14421461
// Fork PR fallback for enriched PRs
14431462
const enrichedPRMap = new Map(enrichedPRs.map(pr => [pr.id, pr]));

0 commit comments

Comments
 (0)