@@ -66,6 +66,7 @@ interface CommunityStatsProviderProps {
6666
6767const GITHUB_ORG = "recodehive" ;
6868const POINTS_PER_PR = 10 ;
69+ const MAX_CONCURRENT_REQUESTS = 5 ; // Limit concurrent requests to avoid rate limiting
6970
7071export function CommunityStatsProvider ( { children } : CommunityStatsProviderProps ) {
7172 const {
@@ -128,6 +129,58 @@ export function CommunityStatsProvider({ children }: CommunityStatsProviderProps
128129 return mergedPRs ;
129130 } , [ ] ) ;
130131
132+ // NEW: Concurrent processing function with controlled concurrency
133+ const processBatch = useCallback ( async (
134+ repos : any [ ] ,
135+ headers : Record < string , string >
136+ ) : Promise < { contributorMap : Map < string , Contributor > ; totalMergedPRs : number } > => {
137+ const contributorMap = new Map < string , Contributor > ( ) ;
138+ let totalMergedPRs = 0 ;
139+
140+ // Process repos in batches to control concurrency
141+ for ( let i = 0 ; i < repos . length ; i += MAX_CONCURRENT_REQUESTS ) {
142+ const batch = repos . slice ( i , i + MAX_CONCURRENT_REQUESTS ) ;
143+
144+ const promises = batch . map ( async ( repo ) => {
145+ if ( repo . archived ) return { mergedPRs : [ ] , repoName : repo . name } ;
146+
147+ try {
148+ const mergedPRs = await fetchMergedPRsForRepo ( repo . name , headers ) ;
149+ return { mergedPRs, repoName : repo . name } ;
150+ } catch ( error ) {
151+ console . warn ( `Skipping repo ${ repo . name } due to error:` , error ) ;
152+ return { mergedPRs : [ ] , repoName : repo . name } ;
153+ }
154+ } ) ;
155+
156+ // Wait for current batch to complete
157+ const results = await Promise . all ( promises ) ;
158+
159+ // Process results from this batch
160+ results . forEach ( ( { mergedPRs } ) => {
161+ totalMergedPRs += mergedPRs . length ;
162+
163+ mergedPRs . forEach ( ( pr ) => {
164+ const username = pr . user . login ;
165+ if ( ! contributorMap . has ( username ) ) {
166+ contributorMap . set ( username , {
167+ username,
168+ avatar : pr . user . avatar_url ,
169+ profile : pr . user . html_url ,
170+ points : 0 ,
171+ prs : 0 ,
172+ } ) ;
173+ }
174+ const contributor = contributorMap . get ( username ) ! ;
175+ contributor . prs ++ ;
176+ contributor . points += POINTS_PER_PR ;
177+ } ) ;
178+ } ) ;
179+ }
180+
181+ return { contributorMap, totalMergedPRs } ;
182+ } , [ fetchMergedPRsForRepo ] ) ;
183+
131184 const fetchAllStats = useCallback ( async ( signal : AbortSignal ) => {
132185 setLoading ( true ) ;
133186 setError ( null ) ;
@@ -143,7 +196,7 @@ export function CommunityStatsProvider({ children }: CommunityStatsProviderProps
143196 Accept : "application/vnd.github.v3+json" ,
144197 } ;
145198
146- // Fetch general organization stats
199+ // Fetch general organization stats (unchanged)
147200 const orgStats : GitHubOrgStats = await githubService . fetchOrganizationStats ( signal ) ;
148201 setGithubStarCount ( orgStats . totalStars ) ;
149202 setGithubContributorsCount ( orgStats . totalContributors ) ;
@@ -152,38 +205,11 @@ export function CommunityStatsProvider({ children }: CommunityStatsProviderProps
152205 setGithubDiscussionsCount ( orgStats . discussionsCount ) ;
153206 setLastUpdated ( new Date ( orgStats . lastUpdated ) ) ;
154207
155- // Fetch leaderboard data
208+ // Fetch leaderboard data with concurrent processing
156209 const repos = await fetchAllOrgRepos ( headers ) ;
157- const contributorMap = new Map < string , Contributor > ( ) ;
158- let totalMergedPRs = 0 ;
159-
160- for ( const repo of repos ) {
161- if ( repo . archived ) continue ;
162- const repoName = repo . name ;
163- try {
164- const mergedPRs = await fetchMergedPRsForRepo ( repoName , headers ) ;
165- totalMergedPRs += mergedPRs . length ;
166-
167- for ( const pr of mergedPRs ) {
168- const username = pr . user . login ;
169- if ( ! contributorMap . has ( username ) ) {
170- contributorMap . set ( username , {
171- username,
172- avatar : pr . user . avatar_url ,
173- profile : pr . user . html_url ,
174- points : 0 ,
175- prs : 0 ,
176- } ) ;
177- }
178- const contributor = contributorMap . get ( username ) ! ;
179- contributor . prs ++ ;
180- contributor . points += POINTS_PER_PR ;
181- }
182- } catch ( repoErr ) {
183- console . warn ( `Skipping repo ${ repoName } due to error:` , repoErr ) ;
184- continue ;
185- }
186- }
210+
211+ // NEW: Use concurrent processing instead of sequential
212+ const { contributorMap, totalMergedPRs } = await processBatch ( repos , headers ) ;
187213
188214 const sortedContributors = Array . from ( contributorMap . values ( ) ) . sort (
189215 ( a , b ) => b . points - a . points || b . prs - a . prs
@@ -210,7 +236,7 @@ export function CommunityStatsProvider({ children }: CommunityStatsProviderProps
210236 } finally {
211237 setLoading ( false ) ;
212238 }
213- } , [ token , fetchAllOrgRepos , fetchMergedPRsForRepo ] ) ;
239+ } , [ token , fetchAllOrgRepos , processBatch ] ) ;
214240
215241 const clearCache = useCallback ( ( ) => {
216242 githubService . clearCache ( ) ;
0 commit comments