Skip to content

⚡ [performance] Add cache revalidation to GitHub Year In Review API calls#360

Open
is0692vs wants to merge 1 commit into
mainfrom
perf-github-year-in-review-9916394064566109213
Open

⚡ [performance] Add cache revalidation to GitHub Year In Review API calls#360
is0692vs wants to merge 1 commit into
mainfrom
perf-github-year-in-review-9916394064566109213

Conversation

@is0692vs

@is0692vs is0692vs commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

💡 What: Replaced cache: "no-store" with next: { revalidate: 86400 } in the GraphQL and REST fetch calls within src/lib/githubYearInReview.ts.

🎯 Why: Historical GitHub activity data for previous years does not change frequently. Fetching this data on every request caused unnecessary I/O latency and consumed API rate limits. Applying a 24-hour cache (86400 seconds) drastically improves response times for repeated requests without sacrificing meaningful freshness.

📊 Measured Improvement: Reusing cached responses via Next.js Data Cache prevents redundant network requests to the GitHub API, reducing overall response latency and avoiding rate limit exhaustion on popular profiles.


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

Greptile Summary

GraphQLおよびREST fetchの cache: "no-store"next: { revalidate: 86400 } に置き換え、GitHubの年次レビューAPIレスポンスを24時間キャッシュするパフォーマンス改善PRです。過去年のデータへの繰り返しリクエストを削減しレート制限の消費を抑える意図は妥当ですが、実装に2点の問題があります。

  • 現在年のデータが最大24時間古くなる: year が現在年の場合でも同じTTLが適用されるため、当日のコントリビューションが反映されない。
  • Authorizationヘッダーのキャッシュキー保証: Next.jsのData CacheがPOST fetchの Authorization ヘッダーをキャッシュキーに含めない場合、異なるユーザーのプライベートコントリビューション情報が混在するリスクがある。

Confidence Score: 3/5

現在年のリクエストで最大24時間古いコントリビューションデータを返すことと、ユーザー固有トークンのキャッシュ分離が未検証であることから、このままマージするのは推奨しません。

現在年に対して24時間キャッシュが無条件に適用されるため、本日行ったコントリビューションが反映されない状態が続く。加えてGitHub GraphQL APIはトークンによって返すデータが異なるにもかかわらず、POSTリクエストのキャッシュキーにAuthorizationヘッダーが含まれる保証がなく、ユーザー間のデータ混在リスクが排除できていない。

src/lib/githubYearInReview.ts — キャッシュTTLと年判定ロジック、およびキャッシュキーのユーザー分離を確認する必要がある。

Security Review

  • 潜在的なユーザー間データ漏洩 (src/lib/githubYearInReview.ts): GitHub GraphQL APIはトークンスコープに基づいてプライベートリポジトリへのアクセスを返す。POSTリクエストのキャッシュキーに Authorization ヘッダーが確実に含まれない場合、ユーザーAのプライベートコントリビューション情報が同じ username/year をリクエストする別ユーザーBに返される可能性がある。

Important Files Changed

Filename Overview
src/lib/githubYearInReview.ts cache: "no-store"next: { revalidate: 86400 } に置換。現在年のデータが24時間古くなる問題と、Authorizationヘッダーがキャッシュキーに含まれない場合の潜在的なユーザー間データ漏洩リスクがある。

Comments Outside Diff (2)

  1. src/lib/githubYearInReview.ts, line 92-98 (link)

    P1 現在年のデータが最大24時間古くなる

    year パラメータが現在の年と一致する場合(例:2025年のリクエスト)、24時間のキャッシュが適用されるため、その日に行われたコントリビューションが最大24時間反映されません。PR説明には「過去年のデータは頻繁に変更されない」と記載されていますが、実装では現在年と過去年の区別が行われていません。

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/lib/githubYearInReview.ts
    Line: 92-98
    
    Comment:
    **現在年のデータが最大24時間古くなる**
    
    `year` パラメータが現在の年と一致する場合(例:2025年のリクエスト)、24時間のキャッシュが適用されるため、その日に行われたコントリビューションが最大24時間反映されません。PR説明には「過去年のデータは頻繁に変更されない」と記載されていますが、実装では現在年と過去年の区別が行われていません。
    
    How can I resolve this? If you propose a fix, please make it concise.
  2. src/lib/githubYearInReview.ts, line 92-98 (link)

    P1 security GitHubレスポンスのキャッシュキーにAuthorizationヘッダーが含まれない可能性

    GitHub GraphQL APIは Authorization ヘッダーによって返すデータが異なります。Next.jsのData CacheがPOSTリクエストのキャッシュキーに Authorization ヘッダーを確実に含めない場合、ユーザーAのプライベートコントリビューション情報が別ユーザーBに返されるリスクがあります。

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/lib/githubYearInReview.ts
    Line: 92-98
    
    Comment:
    **GitHubレスポンスのキャッシュキーにAuthorizationヘッダーが含まれない可能性**
    
    GitHub GraphQL APIは `Authorization` ヘッダーによって返すデータが異なります。Next.jsのData CacheがPOSTリクエストのキャッシュキーに `Authorization` ヘッダーを確実に含めない場合、ユーザーAのプライベートコントリビューション情報が別ユーザーBに返されるリスクがあります。
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
src/lib/githubYearInReview.ts:92-98
**現在年のデータが最大24時間古くなる**

`year` パラメータが現在の年と一致する場合(例:2025年のリクエスト)、24時間のキャッシュが適用されるため、その日に行われたコントリビューションが最大24時間反映されません。PR説明には「過去年のデータは頻繁に変更されない」と記載されていますが、実装では現在年と過去年の区別が行われていません。

### Issue 2 of 2
src/lib/githubYearInReview.ts:92-98
**GitHubレスポンスのキャッシュキーにAuthorizationヘッダーが含まれない可能性**

GitHub GraphQL APIは `Authorization` ヘッダーによって返すデータが異なります。Next.jsのData CacheがPOSTリクエストのキャッシュキーに `Authorization` ヘッダーを確実に含めない場合、ユーザーAのプライベートコントリビューション情報が別ユーザーBに返されるリスクがあります。

Reviews (1): Last reviewed commit: "perf: Add 24-hour cache revalidation to ..." | Re-trigger Greptile

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

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
github-user-summary Ignored Ignored Jun 12, 2026 6:39am

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@dosubot dosubot Bot added the enhancement New feature or request label Jun 12, 2026
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

src/lib/githubYearInReview.ts 内の GitHub API 呼び出し2箇所で、キャッシュ戦略を切り替えました。GraphQL クエリと REST API ベースのコミット活動ヒートマップ取得の両方で、キャッシュをなしから24時間ベースの再検証ポリシーに変更し、エラーハンドリングは保持しています。

Changes

キャッシュ制御の一貫性

Layer / File(s) Summary
キャッシュ再検証設定の統一
src/lib/githubYearInReview.ts
graphql() 呼び出し(94-97行目)と fetchCommitActivityHeatmap() の REST API 呼び出し(319行目)で、キャッシュ制御を cache: "no-store" から next: { revalidate: 86400 } に変更。レート制限対応や失敗時の空ヒートマップ返却を含むステータス/エラーハンドリングは変更されず。

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Possibly related PRs

  • Hiroki-org/github-user-summary#109: このPR と同様に GitHub API 取得時のキャッシュ戦略を next.revalidate: 86400 に変更するものであり、キャッシュ動作の最適化について関連している。

Suggested labels

enhancement, size/S

Poem

🐰 キャッシュを再設計して、

24時間ごとに刷新する

古い情報は払われ落とされ、

新しい年の業績データが輝く✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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.
Description check ❓ Inconclusive PRの説明は変更内容(キャッシュ戦略の切り替え)と目的(パフォーマンス向上)に関連していますが、重大な実装上の問題が指摘されています。 説明では過去年のデータのみをキャッシュ対象としていますが、実装では現在年のデータも同じTTLが適用される点、および Authorization ヘッダーのキャッシュキー保証について、詳細な検証と対応が必要です。
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed タイトルはGraphQL/REST API呼び出しへのキャッシュ再検証追加という主要な変更を明確に要約しており、実装内容と完全に一致しています。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf-github-year-in-review-9916394064566109213

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.

@coderabbitai coderabbitai Bot added the size/S label Jun 12, 2026
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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

Copy link
Copy Markdown

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 replaces cache: 'no-store' with a 24-hour Next.js revalidation cache (86400 seconds) for both GraphQL and REST API requests. The reviewer suggests dynamically adjusting the revalidation period: maintaining the 24-hour cache for past years, but reducing it to 5 minutes for the current year to ensure users see up-to-date contribution and heatmap data.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

headers: headers(token),
body: JSON.stringify({ query, variables }),
cache: "no-store",
next: { revalidate: 86400 },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Caching all GraphQL responses for 24 hours (86400 seconds) is highly efficient for past years, but it causes a significant user experience issue for the current year, where users expect to see their active contributions and heatmaps update more frequently.

We can dynamically determine the revalidation period by checking the year requested in the query variables. If the requested year is in the past, we can cache it for 24 hours. If it is the current year, we should use a shorter revalidation window (e.g., 5 minutes) to keep the data fresh while still protecting against rate limits.

        next: {
            revalidate: (() => {
                const dateStr = (variables.from || variables.since) as string | undefined;
                const year = dateStr ? parseInt(dateStr.slice(0, 4), 10) : undefined;
                return year && year < new Date().getUTCFullYear() ? 86400 : 300;
            })()
        },

url.searchParams.set("per_page", "100");

const res = await fetch(url.toString(), { headers: headers(token), cache: "no-store" });
const res = await fetch(url.toString(), { headers: headers(token), next: { revalidate: 86400 } });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Similar to the GraphQL queries, caching the REST API response for the current year's commit activity for 24 hours will prevent users from seeing their latest commits on the heatmap.

Since the year is directly available in this function, we can dynamically set the revalidation time: 24 hours for past years, and 5 minutes for the current year.

Suggested change
const res = await fetch(url.toString(), { headers: headers(token), next: { revalidate: 86400 } });
const res = await fetch(url.toString(), {
headers: headers(token),
next: { revalidate: year < new Date().getUTCFullYear() ? 86400 : 300 }
});

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/githubYearInReview.ts (1)

92-117: 🧹 Nitpick | 🔵 Trivial | ⚖️ Poor tradeoff

コード重複: src/lib/github.tsgraphql() 関数との重複。

このローカルの graphql() 関数は src/lib/github.ts の同名関数とほぼ同じロジックを持っていますが、revalidation時間が異なります(ここ: 86400s、upstream: 300s)。この divergence は year-in-review 特有のキャッシング要件のためと思われますが、将来的にメンテナンス上の問題を引き起こす可能性があります。

♻️ 提案されるリファクタリング案

Option 1: upstream の graphql() 関数に revalidate パラメータを追加:

// In src/lib/github.ts
export async function graphql<T>(
  query: string, 
  token?: string, 
  variables?: Record<string, unknown>,
  revalidate?: number
): Promise<T> {
  // ... existing code
  const res = await fetch(GITHUB_GRAPHQL, {
    method: "POST",
    headers: headers(token),
    body: JSON.stringify(body),
    next: { revalidate: revalidate ?? 300 },
  });
  // ... rest of code
}

その後、このファイルでは upstream 関数を import して使用:

import { graphql } from "`@/lib/github`";

// In fetchYearInReviewData:
const response = await graphql<YearInReviewResponse>(
  YEAR_IN_REVIEW_QUERY, 
  token, 
  variables,
  86400 // or conditional based on year
);

Option 2: このファイルの graphql()graphqlYearInReview() のような固有名に変更し、目的を明確にする。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/githubYearInReview.ts` around lines 92 - 117, The local graphql() in
src/lib/githubYearInReview.ts duplicates logic from src/lib/github.ts but uses a
different revalidate value; update the upstream graphql in src/lib/github.ts to
accept an optional revalidate parameter (e.g., revalidate?: number) and use it
in the fetch next.revalidate option (defaulting to the current 300), then remove
the local graphql() and import the shared graphql<T> into githubYearInReview and
call it with revalidate = 86400 when fetching YearInReview data; alternatively,
if you prefer file-local clarity, rename the local function to
graphqlYearInReview() and delegate to the upstream graphql or wrap it to only
override revalidate, but prefer the former shared-parameter approach for
maintainability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/githubYearInReview.ts`:
- Line 97: Both GraphQL and REST fetches use a fixed next: { revalidate: 86400 }
which fails to distinguish current year vs past years; update
fetchYearInReviewData and fetchCommitActivityHeatmap to compute whether the
requested year equals the current year (e.g., new Date().getFullYear()) and pass
a shorter revalidate value (e.g., 300) for the current year and 86400 for past
years into the fetch options (replace the hardcoded next: { revalidate: 86400 }
with conditional logic) so current-year data is refreshed frequently while older
years keep the 24h cache.

---

Outside diff comments:
In `@src/lib/githubYearInReview.ts`:
- Around line 92-117: The local graphql() in src/lib/githubYearInReview.ts
duplicates logic from src/lib/github.ts but uses a different revalidate value;
update the upstream graphql in src/lib/github.ts to accept an optional
revalidate parameter (e.g., revalidate?: number) and use it in the fetch
next.revalidate option (defaulting to the current 300), then remove the local
graphql() and import the shared graphql<T> into githubYearInReview and call it
with revalidate = 86400 when fetching YearInReview data; alternatively, if you
prefer file-local clarity, rename the local function to graphqlYearInReview()
and delegate to the upstream graphql or wrap it to only override revalidate, but
prefer the former shared-parameter approach for maintainability.
🪄 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: e78e9b1f-65e5-408c-a150-0f663396e3e9

📥 Commits

Reviewing files that changed from the base of the PR and between a475ecb and bbc2a49.

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

headers: headers(token),
body: JSON.stringify({ query, variables }),
cache: "no-store",
next: { revalidate: 86400 },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

現在年と過去年を区別しない24時間キャッシュの統一的な問題。

src/lib/githubYearInReview.ts の Line 97(GraphQL fetch)と Line 319(REST fetch)の両方で、24時間(86400秒)のキャッシュ再検証が一律適用されています。共通のroot causeは、両方の fetch 呼び出しにおいて、リクエストされた year が過去年か現在年(2026年)かを区別していない点です。

現在年のデータに対して24時間キャッシュを適用すると、ユーザーが今日行ったコントリビューションが最大24時間反映されず、UX が著しく損なわれます。過去年については24時間キャッシュは適切ですが、現在年については短い revalidation 時間(例: 300秒)を使用すべきです。

修正案としては、fetchYearInReviewData および fetchCommitActivityHeatmap 内で年度チェックを追加し、現在年の場合は両方の fetch に異なる revalidation 時間を渡すようにする必要があります。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/githubYearInReview.ts` at line 97, Both GraphQL and REST fetches use
a fixed next: { revalidate: 86400 } which fails to distinguish current year vs
past years; update fetchYearInReviewData and fetchCommitActivityHeatmap to
compute whether the requested year equals the current year (e.g., new
Date().getFullYear()) and pass a shorter revalidate value (e.g., 300) for the
current year and 86400 for past years into the fetch options (replace the
hardcoded next: { revalidate: 86400 } with conditional logic) so current-year
data is refreshed frequently while older years keep the 24h cache.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size/XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant