@@ -1153,14 +1153,101 @@ public async Task RetriesOnTaskCanceledExceptionFromTimeoutThenSucceeds()
11531153 Assert . Equal ( 2 , handler . RequestCount ) ;
11541154 }
11551155
1156+ [ Theory ]
1157+ [ InlineData ( HttpStatusCode . BadGateway ) ] // 502
1158+ [ InlineData ( HttpStatusCode . GatewayTimeout ) ] // 504
1159+ public async Task RetriesOnGatewayHttpStatusCodeThenSucceeds ( HttpStatusCode statusCode )
1160+ {
1161+ var handler = new FakeRetryHttpMessageHandler ( ) ;
1162+ handler . AddResponse ( statusCode , new { type = "error" , detail = "server error" } ) ;
1163+ handler . AddResponse ( HttpStatusCode . OK , new { featureFlags = new { retry_flag = true } } ) ;
1164+ using var httpClient = CreateHttpClient ( handler ) ;
1165+ var options = CreateOptions ( ) ;
1166+ var timeProvider = new FakeTimeProvider ( ) ;
1167+
1168+ var task = httpClient . PostJsonWithNetworkRetryAsync < FlagsApiResult > (
1169+ FlagsUrl ,
1170+ new { api_key = "test" , distinct_id = "user-1" } ,
1171+ timeProvider ,
1172+ options ,
1173+ new FeatureFlagRequestCircuitBreaker ( ) ,
1174+ CancellationToken . None ) ;
1175+
1176+ await handler . WaitForRequestCountAsync ( 1 ) ;
1177+ Assert . Equal ( 1 , handler . RequestCount ) ;
1178+ timeProvider . Advance ( TimeSpan . FromMilliseconds ( 1 ) ) ;
1179+ var result = await task ;
1180+
1181+ Assert . NotNull ( result ) ;
1182+ Assert . NotNull ( result ! . FeatureFlags ) ;
1183+ Assert . True ( result . FeatureFlags ! . TryGetValue ( "retry_flag" , out var retryFlag ) ) ;
1184+ Assert . True ( retryFlag == true ) ;
1185+ Assert . Equal ( 2 , handler . RequestCount ) ;
1186+ }
1187+
1188+ [ Theory ]
1189+ [ InlineData ( HttpStatusCode . BadGateway ) ] // 502
1190+ [ InlineData ( HttpStatusCode . GatewayTimeout ) ] // 504
1191+ public async Task DoesNotRetryGatewayHttpStatusCodeWhenFeatureFlagRequestMaxRetriesIsZero ( HttpStatusCode statusCode )
1192+ {
1193+ var handler = new FakeRetryHttpMessageHandler ( ) ;
1194+ handler . AddResponse ( statusCode , new { type = "error" , detail = "server error" } ) ;
1195+ handler . AddResponse ( HttpStatusCode . OK , new { featureFlags = new { retry_flag = true } } ) ; // Should never be reached
1196+ using var httpClient = CreateHttpClient ( handler ) ;
1197+ var options = CreateOptions ( maxRetries : 0 ) ;
1198+ var timeProvider = new FakeTimeProvider ( ) ;
1199+
1200+ await Assert . ThrowsAsync < ApiException > ( ( ) =>
1201+ httpClient . PostJsonWithNetworkRetryAsync < FlagsApiResult > (
1202+ FlagsUrl ,
1203+ new { api_key = "test" , distinct_id = "user-1" } ,
1204+ timeProvider ,
1205+ options ,
1206+ new FeatureFlagRequestCircuitBreaker ( ) ,
1207+ CancellationToken . None ) ) ;
1208+
1209+ Assert . Equal ( 1 , handler . RequestCount ) ;
1210+ }
1211+
1212+ [ Theory ]
1213+ [ InlineData ( HttpStatusCode . BadGateway ) ] // 502
1214+ [ InlineData ( HttpStatusCode . GatewayTimeout ) ] // 504
1215+ public async Task ThrowsAfterFeatureFlagRequestMaxRetriesWhenGatewayHttpStatusCodesKeepFailing (
1216+ HttpStatusCode statusCode )
1217+ {
1218+ var handler = new FakeRetryHttpMessageHandler ( ) ;
1219+ handler . AddResponse ( statusCode , new { type = "error" , detail = "server error" } ) ;
1220+ handler . AddResponse ( statusCode , new { type = "error" , detail = "server error" } ) ;
1221+ handler . AddResponse ( statusCode , new { type = "error" , detail = "server error" } ) ;
1222+ using var httpClient = CreateHttpClient ( handler ) ;
1223+ var options = CreateOptions ( maxRetries : 2 ) ;
1224+ var timeProvider = new FakeTimeProvider ( ) ;
1225+
1226+ var task = httpClient . PostJsonWithNetworkRetryAsync < FlagsApiResult > (
1227+ FlagsUrl ,
1228+ new { api_key = "test" , distinct_id = "user-1" } ,
1229+ timeProvider ,
1230+ options ,
1231+ new FeatureFlagRequestCircuitBreaker ( ) ,
1232+ CancellationToken . None ) ;
1233+
1234+ for ( var i = 1 ; i <= 3 && ! task . IsCompleted ; i ++ )
1235+ {
1236+ await handler . WaitForRequestCountAsync ( i ) ;
1237+ timeProvider . Advance ( TimeSpan . FromSeconds ( 1 ) ) ;
1238+ }
1239+
1240+ var exception = await Assert . ThrowsAsync < ApiException > ( ( ) => task ) ;
1241+ Assert . Equal ( statusCode , exception . Status ) ;
1242+ Assert . Equal ( 3 , handler . RequestCount ) ;
1243+ }
1244+
11561245 [ Theory ]
11571246 [ InlineData ( HttpStatusCode . RequestTimeout ) ] // 408
11581247 [ InlineData ( HttpStatusCode . TooManyRequests ) ] // 429
11591248 [ InlineData ( HttpStatusCode . InternalServerError ) ] // 500
1160- [ InlineData ( HttpStatusCode . BadGateway ) ] // 502
11611249 [ InlineData ( HttpStatusCode . ServiceUnavailable ) ] // 503
1162- [ InlineData ( HttpStatusCode . GatewayTimeout ) ] // 504
1163- public async Task DoesNotRetryOnHttpErrorStatusCodes ( HttpStatusCode statusCode )
1250+ public async Task DoesNotRetryOnOtherHttpErrorStatusCodes ( HttpStatusCode statusCode )
11641251 {
11651252 var handler = new FakeRetryHttpMessageHandler ( ) ;
11661253 handler . AddResponse ( statusCode , new { type = "error" , detail = "server error" } ) ;
0 commit comments