1- using Sudoku . Blazor . Services ;
1+ using Microsoft . Extensions . Http . Resilience ;
2+ using Sudoku . Blazor . Services ;
23using Sudoku . Blazor . Services . Abstractions ;
34using Sudoku . Blazor . Services . HttpClients ;
45
@@ -19,38 +20,37 @@ public static IServiceCollection RegisterBlazorGameServices(this IServiceCollect
1920 . AddScoped < IGameTimer > ( sp => new GameTimer ( TimeSpan . FromSeconds ( 1 ) ) ) ;
2021
2122 var apiBaseUrl = config [ "ApiBaseUrl" ] ;
22-
23+
24+ // Shared resilience configuration for all API clients.
25+ // Tweak these values while testing to find the right balance.
26+ static void ConfigureResilience ( HttpStandardResilienceOptions options )
27+ {
28+ // Per-attempt timeout.
29+ options . AttemptTimeout . Timeout = TimeSpan . FromSeconds ( 20 ) ;
30+
31+ // 0 retries = 1 total attempt. Bump this as needed while testing.
32+ options . Retry . MaxRetryAttempts = 1 ;
33+
34+ // TotalRequestTimeout must be strictly greater than AttemptTimeout.
35+ // Keep it at least AttemptTimeout * (MaxRetryAttempts + 1) + a small buffer.
36+ options . TotalRequestTimeout . Timeout = TimeSpan . FromSeconds ( 25 ) ;
37+
38+ // CircuitBreaker.SamplingDuration must be >= 2 * AttemptTimeout.
39+ options . CircuitBreaker . SamplingDuration = TimeSpan . FromSeconds ( 60 ) ;
40+ }
41+
2342 services . AddHttpClient < IGameApiClient , GameApiClient > ( client =>
2443 {
2544 client . BaseAddress = new Uri ( apiBaseUrl ) ;
2645 } )
27- . AddStandardResilienceHandler ( options =>
28- {
29- // Configure retry policy to only retry idempotent methods (GET, HEAD, OPTIONS, etc.)
30- options . Retry . ShouldHandle = args =>
31- {
32- // Only retry for GET requests
33- if ( args . Outcome . Result ? . RequestMessage ? . Method == HttpMethod . Get )
34- {
35- return ValueTask . FromResult ( args . Outcome . Result . StatusCode >= System . Net . HttpStatusCode . InternalServerError ) ;
36- }
37-
38- // Don't retry POST, PUT, DELETE, PATCH
39- return ValueTask . FromResult ( false ) ;
40- } ;
41-
42- // Reduce max retry attempts
43- options . Retry . MaxRetryAttempts = 2 ;
44- options . Retry . Delay = TimeSpan . FromMilliseconds ( 500 ) ;
45- } ) ;
46-
47- // Configure HttpClient for PlayerApiClient with the same logic
46+ . AddStandardResilienceHandler ( ConfigureResilience ) ;
47+
4848 services . AddHttpClient < IPlayerApiClient , PlayerApiClient > ( client =>
4949 {
5050 client . BaseAddress = new Uri ( apiBaseUrl ) ;
5151 } )
52- . AddStandardResilienceHandler ( ) ;
53-
52+ . AddStandardResilienceHandler ( ConfigureResilience ) ;
53+
5454 return services ;
5555 }
5656 }
0 commit comments