@@ -32,18 +32,74 @@ public GitHubGraphQLClient(GitHubPat pat, string userAgent)
3232
3333 public async Task < GraphQLResponse < T > ? > SendAsync < T > ( GraphQLRequest request )
3434 {
35- using var httpResponse = await HttpClient . PostAsJsonAsync ( requestUri : ( string ? ) null , request ) ;
35+ HttpResponseMessage ? httpResponse ;
3636
37- var rateLimitLimit = httpResponse . Headers . GetValues ( "X-RateLimit-Limit" ) . SingleOrDefault ( ) ;
38- var rateLimitRemaining = httpResponse . Headers . GetValues ( "X-RateLimit-Remaining" ) . SingleOrDefault ( ) ;
39- var rateLimitReset = long . Parse ( httpResponse . Headers . GetValues ( "X-RateLimit-Reset" ) . Single ( ) ) ;
40- var resetTime = DateTime . UnixEpoch . AddSeconds ( rateLimitReset ) ;
41- Console . WriteLine ( $ "GraphQL HTTP rate-limit = { rateLimitLimit } , remaining = { rateLimitRemaining } , reset = { resetTime : o} ") ;
37+ int attempt = 0 ;
38+ int maxAttempts = 5 ;
39+ TimeSpan delay = TimeSpan . FromSeconds ( 1 ) ;
4240
43- using var stream = await httpResponse . Content . ReadAsStreamAsync ( ) ;
44- GraphQLResponse < T > ? response = await JsonSerializer . DeserializeAsync < GraphQLResponse < T > > ( stream ) ;
41+ for ( ; ; )
42+ {
43+ httpResponse = null ;
44+ try
45+ {
46+ httpResponse = await HttpClient . PostAsJsonAsync ( requestUri : ( string ? ) null , request ) ;
47+
48+ var rateLimitLimit = httpResponse . Headers . GetValues ( "X-RateLimit-Limit" ) . SingleOrDefault ( ) ;
49+ var rateLimitRemaining = httpResponse . Headers . GetValues ( "X-RateLimit-Remaining" ) . SingleOrDefault ( ) ;
50+ var rateLimitReset = long . Parse ( httpResponse . Headers . GetValues ( "X-RateLimit-Reset" ) . Single ( ) ) ;
51+ var resetTime = DateTime . UnixEpoch . AddSeconds ( rateLimitReset ) ;
52+ Console . WriteLine ( $ "GraphQL HTTP rate-limit = { rateLimitLimit } , remaining = { rateLimitRemaining } , reset = { resetTime : o} ") ;
53+
54+ using var stream = await httpResponse . Content . ReadAsStreamAsync ( ) ;
55+ GraphQLResponse < T > ? response = await JsonSerializer . DeserializeAsync < GraphQLResponse < T > > ( stream ) ;
56+
57+ httpResponse . Dispose ( ) ;
58+
59+ return response ;
60+ }
61+ catch ( Exception ex )
62+ {
63+ Console . WriteLine ( $ "GraphQL HTTP error: { ex . Message } ") ;
64+
65+ TimeSpan retryAfter = delay ;
66+ if ( httpResponse != null )
67+ {
68+ Console . WriteLine ( httpResponse ) ;
4569
46- return response ;
70+ if ( httpResponse . Content . Headers . ContentLength < 2000 )
71+ {
72+ var body = await httpResponse . Content . ReadAsStringAsync ( ) ;
73+ Console . WriteLine ( body ) ;
74+ }
75+
76+ if ( httpResponse . Headers ? . RetryAfter ? . Date != null )
77+ {
78+ retryAfter = httpResponse . Headers . RetryAfter . Date . Value - DateTime . UtcNow ;
79+ if ( retryAfter < TimeSpan . Zero )
80+ {
81+ retryAfter = delay ;
82+ }
83+ }
84+ else if ( httpResponse . Headers ? . RetryAfter ? . Delta != null )
85+ {
86+ retryAfter = httpResponse . Headers . RetryAfter . Delta . Value ;
87+ }
88+
89+ httpResponse . Dispose ( ) ;
90+ }
91+
92+ if ( attempt >= maxAttempts )
93+ {
94+ throw ;
95+ }
96+
97+ Console . WriteLine ( $ "GraphQL HTTP retrying in { retryAfter . TotalSeconds } seconds...") ;
98+ await Task . Delay ( retryAfter ) ;
99+ attempt ++ ;
100+ delay += delay ;
101+ }
102+ }
47103 }
48104 }
49105}
0 commit comments