@@ -157,7 +157,7 @@ export async function getPathsWithMatchingStrings(strArr, org, repo) {
157157
158158async function searchCode ( q , perPage , currentPage ) {
159159 try {
160- const { data } = await github . rest . search . code ( {
160+ const { data } = await secondaryRateLimitRetry ( github . rest . search . code , {
161161 q,
162162 per_page : perPage ,
163163 page : currentPage ,
@@ -169,3 +169,41 @@ async function searchCode(q, perPage, currentPage) {
169169 throw err
170170 }
171171}
172+
173+ async function secondaryRateLimitRetry ( callable , args , maxAttempts = 5 ) {
174+ try {
175+ const response = await callable ( args )
176+ return response
177+ } catch ( err ) {
178+ // If you get a secondary rate limit error (403) you'll get a data
179+ // response that includes:
180+ //
181+ // {
182+ // documentation_url: 'https://docs.github.com/en/free-pro-team@latest/rest/overview/resources-in-the-rest-api#secondary-rate-limits',
183+ // message: 'You have exceeded a secondary rate limit. Please wait a few minutes before you try again.'
184+ // }
185+ //
186+ // Let's look for that an manually self-recurse, under certain conditions
187+ const lookFor = 'You have exceeded a secondary rate limit.'
188+ const sleepTime = 5000 // ms
189+ if (
190+ err . status &&
191+ err . status === 403 &&
192+ err . response ?. data ?. message . includes ( lookFor ) &&
193+ maxAttempts > 0
194+ ) {
195+ console . warn (
196+ `Got secondary rate limit blocked. Sleeping for ${
197+ sleepTime / 1000
198+ } seconds. (attempts left: ${ maxAttempts } )`
199+ )
200+ return new Promise ( ( resolve ) => {
201+ setTimeout ( ( ) => {
202+ resolve ( secondaryRateLimitRetry ( callable , args , maxAttempts - 1 ) )
203+ } , sleepTime )
204+ } )
205+ }
206+
207+ throw err
208+ }
209+ }
0 commit comments