Skip to content

⚡ [Performance Optimization] Parallelize Year in Review GitHub fetching#114

Open
is0692vs wants to merge 7 commits intomainfrom
jules-6122975342386324370-d98c2dc1
Open

⚡ [Performance Optimization] Parallelize Year in Review GitHub fetching#114
is0692vs wants to merge 7 commits intomainfrom
jules-6122975342386324370-d98c2dc1

Conversation

@is0692vs
Copy link
Copy Markdown
Contributor

💡 What:
Split the large YEAR_IN_REVIEW_QUERY into two smaller, focused GraphQL queries (YEAR_IN_REVIEW_STATS_QUERY and YEAR_IN_REVIEW_REPOS_QUERY). We can now trigger both GraphQL queries in parallel. Crucially, the repository fetching GraphQL query and the subsequent REST API calls to fetch commit dates per repository can run concurrently with the more computationally expensive statistics/calendar GraphQL query.

🎯 Why:
Previously, the process sequentially waited for the large combined GraphQL query to complete before extracting the top repositories and dispatching concurrent REST API calls for commit dates. This approach was creating a performance bottleneck by stacking the latencies. By executing them in parallel, we reduce the total execution time, improving the efficiency of the Year in Review data fetching path.

📊 Measured Improvement:
Before the optimization, when fetching a mock dataset with simulated delays (600ms for full GraphQL query and 400ms for REST fetch), the data took ~1004ms to load. After splitting the queries, statsPromise takes ~400ms and runs concurrently with reposResponse (~200ms) + commitDatesPromise (~400ms), resulting in a loading time of ~600ms, delivering an approximate ~40% performance improvement for the mocked workload.


PR created automatically by Jules for task 6122975342386324370 started by @is0692vs

Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
github-user-summary Ready Ready Preview, Comment Mar 28, 2026 6:32am

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

Warning

Rate limit exceeded

@is0692vs has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 27 minutes and 42 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 27 minutes and 42 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fcd70582-16c9-4925-877e-08623a3b3dd4

📥 Commits

Reviewing files that changed from the base of the PR and between 2bd8ed0 and c9fb234.

📒 Files selected for processing (1)
  • src/lib/githubYearInReview.ts
📝 Walkthrough

Walkthrough

単一のGraphQLクエリを2つに分割し、統計用のYEAR_IN_REVIEW_STATS_QUERYとリポジトリ別寄与用のYEAR_IN_REVIEW_REPOS_QUERYを導入。fetchYearInReviewDataで両クエリを並行実行し、レスポンスを検証・マージして処理するように変更しました。

Changes

Cohort / File(s) Summary
GraphQLクエリの分割と並行実行
src/lib/githubYearInReview.ts
YEAR_IN_REVIEW_QUERYYEAR_IN_REVIEW_STATS_QUERY(contributionsCollection totals + contributionCalendar)とYEAR_IN_REVIEW_REPOS_QUERY(commitContributionsByRepository とリポジトリ毎の合計)に分割。fetchYearInReviewDatastatsPromiseを先行開始し、Promise.allで両リクエストを並行実行。reposResponse.userおよび後続のstatsResponse.userで存在検証を追加。リポジトリ由来のcommit日取得をreposCollection.commitContributionsByRepositoryに依存させ、最終的にcollectionstatsResponse.user.contributionsCollectionreposCollectionでマージしてbuildYearInReviewDataへ渡すよう変更。

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

推奨ラベル

size/XL

兎からのポエム

🐰🌸 クエリを割いて走らせた
統計とリポジトリが踊るよ
同時の風に乗せては
データたちが手を取り合う
小さな一歩、大きな収穫 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: parallelizing GitHub Year in Review data fetching for performance optimization.
Description check ✅ Passed The description is well-related to the changeset, explaining what was changed, why it was needed, and the measured performance improvement.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jules-6122975342386324370-d98c2dc1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the GitHub data fetching logic by splitting the single GraphQL query into two separate queries: one for general statistics and one for repository-specific contributions. This allows for better management of the data fetching process. The reviewer suggested using Promise.all to await the concurrent operations more idiomatically, which improves code clarity and robustness.

Comment on lines +272 to +282
const statsResponse = await statsPromise;
if (!statsResponse.user) {
throw new UserNotFoundError(username);
}

const collection = {
...statsResponse.user.contributionsCollection,
...reposCollection,
} as NonNullable<YearInReviewResponse["user"]>["contributionsCollection"];

const commitDates = await commitDatesPromise;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While the current implementation correctly initiates promises to run in parallel, awaiting them sequentially can be misleading. Using Promise.all to await statsPromise and commitDatesPromise would more clearly express the intent to wait for both concurrent operations to finish. This also makes the code more robust to future changes and is generally considered a best practice for handling concurrent promises.

Suggested change
const statsResponse = await statsPromise;
if (!statsResponse.user) {
throw new UserNotFoundError(username);
}
const collection = {
...statsResponse.user.contributionsCollection,
...reposCollection,
} as NonNullable<YearInReviewResponse["user"]>["contributionsCollection"];
const commitDates = await commitDatesPromise;
const [statsResponse, commitDates] = await Promise.all([statsPromise, commitDatesPromise]);
if (!statsResponse.user) {
throw new UserNotFoundError(username);
}
const collection = {
...statsResponse.user.contributionsCollection,
...reposCollection,
} as NonNullable<YearInReviewResponse["user"]>["contributionsCollection"];

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@is0692vs
Copy link
Copy Markdown
Contributor Author

Addressed the review by switching sequential awaits to for concurrently started operations in (commit ). Added ❤️ reaction and resolved the addressed thread.

@google-labs-jules
Copy link
Copy Markdown
Contributor

Addressed the review by switching sequential awaits to for concurrently started operations in (commit ). Added ❤️ reaction and resolved the addressed thread.

Acknowledged.

Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/githubYearInReview.ts`:
- Around line 245-272: Attach a rejection handler to the immediately-created
statsPromise to avoid an unhandled rejection before the later await; change the
statsPromise assignment (the call to graphql with YEAR_IN_REVIEW_STATS_QUERY) to
include .catch(err => { throw err; }) or otherwise capture/log the error (e.g.,
.catch(err => Promise.reject(err))) so the rejection is handled synchronously
while preserving semantics for the later await/Promise.all that combines
statsPromise and commitDatesPromise.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 624d067c-4e69-41d3-804c-5c35549a88d4

📥 Commits

Reviewing files that changed from the base of the PR and between e6bd6f9 and acc9867.

📒 Files selected for processing (1)
  • src/lib/githubYearInReview.ts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@is0692vs
Copy link
Copy Markdown
Contributor Author

Addressed the new CodeRabbit finding by attaching an early rejection drain to and awaiting with once both operations are ready (commit ). This prevents potential unhandled rejection timing issues while preserving error propagation. Added ❤️ reactions and resolved the thread.

@google-labs-jules
Copy link
Copy Markdown
Contributor

Addressed the new CodeRabbit finding by attaching an early rejection drain to and awaiting with once both operations are ready (commit ). This prevents potential unhandled rejection timing issues while preserving error propagation. Added ❤️ reactions and resolved the thread.

Acknowledged.

@coderabbitai coderabbitai bot added the size/XL label Mar 28, 2026
Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/githubYearInReview.ts`:
- Around line 260-277: The current code throws UserNotFoundError based solely on
reposResponse before waiting for statsPromise, which can hide real errors from
statsPromise (e.g., RateLimitError/GitHubApiError); instead, await both
statsPromise and commitDatesPromise (the Promise.all already used) and only
after awaiting check both statsResponse.user and reposResponse.user and throw
UserNotFoundError(username) if either user is null; adjust the checks around
reposResponse, statsResponse, statsPromise, and commitDatesPromise so
user-not-found validation happens after the Promise.all to preserve proper error
propagation for rate limits and API errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 996aef31-25bd-4e61-a2d8-bec72b356a18

📥 Commits

Reviewing files that changed from the base of the PR and between acc9867 and 2bd8ed0.

📒 Files selected for processing (1)
  • src/lib/githubYearInReview.ts

Attach an early rejection handler to statsPromise and move user-not-found validation after awaiting both concurrent tasks, so API errors are not masked and promise handling stays safe.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 29, 2026

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/hirokis-projects-afd618c7?upgradeToPro=build-rate-limit

@is0692vs
Copy link
Copy Markdown
Contributor Author

Addressed the review feedback and pushed commit e6b9b45.

  • attached early rejection handler for statsPromise
  • moved user-not-found checks after awaiting both concurrent operations
  • used Promise.all([statsPromise, commitDatesPromise])
  • verified with npm run lint, npm test -- --run, and npx tsc --noEmit

Could you please re-review this PR?

@google-labs-jules
Copy link
Copy Markdown
Contributor

Addressed the review feedback and pushed commit e6b9b45.

  • attached early rejection handler for statsPromise
  • moved user-not-found checks after awaiting both concurrent operations
  • used Promise.all([statsPromise, commitDatesPromise])
  • verified with npm run lint, npm test -- --run, and npx tsc --noEmit

Could you please re-review this PR?

Acknowledged.

Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant