-
Notifications
You must be signed in to change notification settings - Fork 0
β‘ perf: deduplicate concurrent GitHub API requests #489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,9 @@ | |||||
| import { getClientIp } from "@/lib/rateLimit"; | ||||||
|
|
||||||
| export const runtime = "edge"; | ||||||
|
|
||||||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||||
| const inflightRequests = new Map<string, Promise<any>>(); | ||||||
| const rateLimiter = new RateLimiter(50, 60 * 1000); | ||||||
| const ONE_HOUR_IN_SECONDS = 60 * 60; | ||||||
| const ONE_DAY_IN_SECONDS = 24 * ONE_HOUR_IN_SECONDS; | ||||||
|
|
@@ -42,15 +45,30 @@ | |||||
| let publicRepos = 0; | ||||||
|
|
||||||
| try { | ||||||
| const res = await fetch(`https://api.github.com/users/${encodeURIComponent(username)}`, { | ||||||
| headers: { | ||||||
| Accept: "application/vnd.github.v3+json", | ||||||
| "User-Agent": "github-user-summary", | ||||||
| }, | ||||||
| next: { revalidate: ONE_DAY_IN_SECONDS }, | ||||||
| }); | ||||||
| if (res.ok) { | ||||||
| const data = await res.json(); | ||||||
| let fetchPromise = inflightRequests.get(username); | ||||||
| if (!fetchPromise) { | ||||||
| fetchPromise = (async () => { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add an explicit return type to the anonymous async function to ensure type safety and adhere to the TypeScript guidelines.
Suggested change
References
|
||||||
| try { | ||||||
| const res = await fetch(`https://api.github.com/users/${encodeURIComponent(username)}`, { | ||||||
| headers: { | ||||||
| Accept: "application/vnd.github.v3+json", | ||||||
| "User-Agent": "github-user-summary", | ||||||
| }, | ||||||
| next: { revalidate: ONE_DAY_IN_SECONDS }, | ||||||
| }); | ||||||
| if (res.ok) { | ||||||
| return await res.json(); | ||||||
| } | ||||||
| return null; | ||||||
|
Comment on lines
+61
to
+62
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the first in-flight GitHub request for a username returns a temporary non-OK response, this promise resolves to Prompt To Fix With AIThis is a comment left during a code review.
Path: src/app/api/og/[username]/route.tsx
Line: 61-62
Comment:
**Shared Failure Result**
When the first in-flight GitHub request for a username returns a temporary non-OK response, this promise resolves to `null` and every concurrent caller renders the fallback OG image. Before this change, those callers fetched independently, so a later concurrent request could still return real profile data instead of sharing the first transient failure.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! |
||||||
| } finally { | ||||||
| inflightRequests.delete(username); | ||||||
| } | ||||||
| })(); | ||||||
| inflightRequests.set(username, fetchPromise); | ||||||
| } | ||||||
|
|
||||||
| const data = await fetchPromise; | ||||||
| if (data) { | ||||||
| name = data.name ?? username; | ||||||
| bio = data.bio ?? ""; | ||||||
| avatarUrl = data.avatar_url ?? ""; | ||||||
|
|
@@ -84,7 +102,7 @@ | |||||
| }} | ||||||
| > | ||||||
| {avatarUrl && ( | ||||||
| <img | ||||||
|
Check warning on line 105 in src/app/api/og/[username]/route.tsx
|
||||||
| src={sanitizeUrl(avatarUrl)} | ||||||
| alt="" | ||||||
| width={120} | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mock implementation returns a Promise but is not defined as an
asyncfunction, and it lacks an explicit return type. To align with the repository's TypeScript guidelines, please update it to be anasyncfunction with an explicit return type.References