@@ -16,6 +16,8 @@ def initialize(app, options = {})
1616 @last_request_time = Time . now
1717 @mutex = Mutex . new
1818 @debug_enabled = !ENV [ 'THROTTLE_DEBUG' ] . nil? && !ENV [ 'THROTTLE_DEBUG' ] . empty?
19+ @github_rate_limit_remaining = nil
20+ @github_rate_limit_reset = nil
1921 end
2022
2123 def call ( env )
@@ -24,11 +26,43 @@ def call(env)
2426 log_throttle_status
2527 end
2628
27- @app . call ( env )
29+ response = @app . call ( env )
30+
31+ # Update GitHub rate limit info from response headers
32+ @mutex . synchronize do
33+ update_github_rate_limit ( response )
34+ end
35+
36+ response
2837 end
2938
3039 private
3140
41+ def update_github_rate_limit ( response )
42+ if response . headers [ 'x-ratelimit-remaining' ]
43+ @github_rate_limit_remaining = response . headers [ 'x-ratelimit-remaining' ] . to_i
44+ @github_rate_limit_reset = response . headers [ 'x-ratelimit-reset' ] . to_i if response . headers [ 'x-ratelimit-reset' ]
45+ end
46+ end
47+
48+ def calculate_dynamic_delay
49+ return MIN_DELAY_SECONDS unless @github_rate_limit_remaining && @github_rate_limit_reset
50+
51+ # Calculate time until rate limit resets
52+ current_time = Time . now . to_i
53+ time_until_reset = [ @github_rate_limit_reset - current_time , 1 ] . max
54+
55+ # Calculate required delay to not exceed remaining requests
56+ if @github_rate_limit_remaining > 0
57+ required_delay = time_until_reset . to_f / @github_rate_limit_remaining
58+ # Use the more conservative delay (either our standard delay or the calculated one)
59+ [ MIN_DELAY_SECONDS , required_delay ] . max
60+ else
61+ # No requests remaining, wait until reset
62+ time_until_reset
63+ end
64+ end
65+
3266 def throttle_request
3367 current_time = Time . now
3468
@@ -39,11 +73,16 @@ def throttle_request
3973 @last_request_time = current_time
4074 end
4175
42- # Ensure minimum delay between requests to maintain steady rate under 5000/hour
76+ # Use dynamic delay based on actual GitHub rate limit if available
77+ required_delay = @github_rate_limit_remaining ? calculate_dynamic_delay : MIN_DELAY_SECONDS
78+
79+ # Ensure minimum delay between requests
4380 time_since_last = current_time - @last_request_time
44- if time_since_last < MIN_DELAY_SECONDS
45- sleep_time = MIN_DELAY_SECONDS - time_since_last
81+ if time_since_last < required_delay
82+ sleep_time = required_delay - time_since_last
4683 if sleep_time > 0
84+ #delay_reason = @github_rate_limit_remaining ? "dynamic" : "standard"
85+ #$stderr.print "Throttling: waiting #{sleep_time.round(2)}s (#{delay_reason} delay)\n"
4786 sleep ( sleep_time )
4887 end
4988 end
@@ -55,7 +94,8 @@ def throttle_request
5594 if @request_count % 1000 == 0
5695 elapsed_hour = @last_request_time - @hour_start_time
5796 current_rate = elapsed_hour > 0 ? ( @request_count / elapsed_hour * 3600 ) . round ( 1 ) : 0
58- $stderr. print "Throttling status: #{ @request_count } requests in #{ elapsed_hour . round ( 1 ) } s (#{ current_rate } /hour rate)\n "
97+ github_info = @github_rate_limit_remaining ? " GitHub: #{ @github_rate_limit_remaining } remaining" : ""
98+ $stderr. print "Throttling status: #{ @request_count } requests in #{ elapsed_hour . round ( 1 ) } s (#{ current_rate } /hour rate)#{ github_info } \n "
5999 end
60100 end
61101
@@ -264,8 +304,22 @@ def member_activity
264304
265305 # for each repo
266306 @repositories . each do |repo |
267- rate_limit = @client . rate_limit
268- info "rate limit remaining: #{ rate_limit . remaining } /#{ rate_limit . limit } "
307+ # Show rate limit from last response headers (more efficient than API call)
308+ if @client . last_response
309+ remaining = @client . last_response . headers [ 'x-ratelimit-remaining' ]
310+ limit = @client . last_response . headers [ 'x-ratelimit-limit' ]
311+ if remaining && limit
312+ reset_time = @client . last_response . headers [ 'x-ratelimit-reset' ]
313+ if reset_time
314+ minutes_until_reset = [ ( reset_time . to_i - Time . now . to_i ) / 60.0 , 0 ] . max . round ( 1 )
315+ reset_info = " (resets in #{ minutes_until_reset } min)"
316+ else
317+ reset_info = ""
318+ end
319+ info "#{ remaining } requests remaining#{ reset_info } "
320+ end
321+ end
322+
269323 info "analyzing #{ repo } "
270324
271325 commit_activity ( repo )
@@ -342,13 +396,13 @@ def member_activity
342396 builder . use Octokit ::Middleware ::FollowRedirects
343397 builder . use Octokit ::Response ::RaiseError
344398 builder . use Octokit ::Response ::FeedParser
345- builder . response :logger
399+ builder . response :logger if @debug
346400 builder . adapter Faraday . default_adapter
347401end
348402
349403Octokit . configure do |kit |
350404 kit . auto_paginate = true
351- kit . middleware = stack if @debug
405+ kit . middleware = stack
352406end
353407
354408options [ :client ] = Octokit ::Client . new
0 commit comments