@@ -62,6 +62,12 @@ const GRAPHQL_TEMPLATE = `
6262 }
6363 }
6464 }
65+ rateLimit {
66+ limit
67+ remaining
68+ used
69+ resetAt
70+ }
6571}
6672`
6773
@@ -100,6 +106,13 @@ type GhLanguageNode struct {
100106 Name string `json:"name"`
101107}
102108
109+ type RateLimit struct {
110+ Limit int `json:"limit"`
111+ Remaining int `json:"remaining"`
112+ Used int `json:"used"`
113+ ResetAt string `json:"resetAt"`
114+ }
115+
103116type GhQuery struct {
104117 Data struct {
105118 Viewer struct {
@@ -111,6 +124,7 @@ type GhQuery struct {
111124 } `json:"pageInfo"`
112125 } `json:"starredRepositories"`
113126 } `json:"viewer"`
127+ RateLimit RateLimit `json:"rateLimit"`
114128 } `json:"data"`
115129}
116130
@@ -132,6 +146,8 @@ func (ghs *GhStarsService) GetStaredRepos(ctx context.Context) ([]Repo, error) {
132146 return nil , err
133147 }
134148
149+ log .Debug ("Remaining rate limit" , "remaining" , response .Data .RateLimit .Remaining )
150+
135151 result = append (result , mapGhQueryToHelpWantedIssue (response )... )
136152
137153 if response .Data .Viewer .StarredRepositories .PageInfo .HasNextPage {
@@ -199,41 +215,14 @@ func (ghs *GhStarsService) fetchQueryResults(ctx context.Context, cursor string)
199215 req .Header .Set ("Content-Type" , "application/json" )
200216
201217 // Send the request
202- resp , err := doWithRetry (httpClient , req )
218+ ghResponse , err := doWithRetry (httpClient , req )
203219 if err != nil {
204220 log .Error ("Error sending request: %v" , err )
205221
206222 return GhQuery {}, err
207223 }
208- defer closeBody (resp .Body )
209224
210- return processResponse (resp )
211- }
212-
213- func processResponse (resp * http.Response ) (GhQuery , error ) {
214- if resp .StatusCode != http .StatusOK {
215- log .Error ("Error sending request" , "status" , resp .Status )
216-
217- return GhQuery {}, ErrUnexpectedStatusCode
218- }
219-
220- // Read the response
221- body , err := io .ReadAll (resp .Body )
222- if err != nil {
223- log .Error ("Error reading response: %v" , err )
224-
225- return GhQuery {}, fmt .Errorf ("failed to read response: %w" , err )
226- }
227-
228- var queryResult GhQuery
229-
230- if err = json .Unmarshal (body , & queryResult ); err != nil {
231- log .Error ("Error unmarshaling response: %v" , err )
232-
233- return GhQuery {}, fmt .Errorf ("failed to unmarshal response: %w" , err )
234- }
235-
236- return queryResult , nil
225+ return responseToResult (ghResponse )
237226}
238227
239228func doWithRetry (httpclient * http.Client , req * http.Request ) (* http.Response , error ) {
@@ -245,6 +234,22 @@ func doWithRetry(httpclient *http.Client, req *http.Request) (*http.Response, er
245234 return resp , nil
246235 }
247236
237+ if resp .StatusCode == http .StatusTooManyRequests {
238+ log .Warn ("Rate limit exceeded, wait until reset..." )
239+
240+ queryRes , err := responseToResult (resp )
241+ if err != nil {
242+ return nil , err
243+ }
244+
245+ resetTime , err := ParseGhDate (queryRes .Data .RateLimit .ResetAt )
246+ if err != nil {
247+ return nil , err
248+ }
249+ // Wait until the rate limit is reset
250+ time .Sleep (time .Until (resetTime ))
251+ }
252+
248253 if err == nil {
249254 log .Warn ("Github server error" , "status" , resp .StatusCode )
250255 }
@@ -258,8 +263,37 @@ func doWithRetry(httpclient *http.Client, req *http.Request) (*http.Response, er
258263 }
259264}
260265
266+ func responseToResult (resp * http.Response ) (GhQuery , error ) {
267+ queryResult := GhQuery {}
268+
269+ body , err := io .ReadAll (resp .Body )
270+ if err != nil {
271+ log .Errorf ("Error reading rate limited body : %v" , err )
272+
273+ return queryResult , fmt .Errorf ("failed to read response: %w" , err )
274+ }
275+ defer closeBody (resp .Body )
276+
277+ if err = json .Unmarshal (body , & queryResult ); err != nil {
278+ log .Error ("Error unmarshaling response: %v" , err )
279+
280+ return queryResult , fmt .Errorf ("failed to unmarshal response: %w" , err )
281+ }
282+
283+ return queryResult , nil
284+ }
285+
261286func closeBody (body io.ReadCloser ) {
262287 if err := body .Close (); err != nil {
263288 log .Warn ("Error closing response body: %v" , err )
264289 }
265290}
291+
292+ func ParseGhDate (date string ) (time.Time , error ) {
293+ t , err := time .Parse (time .RFC3339 , date )
294+ if err != nil {
295+ return time.Time {}, fmt .Errorf ("failed to parse date: %w" , err )
296+ }
297+
298+ return t , nil
299+ }
0 commit comments