@@ -596,6 +596,83 @@ public async Task ClientRetryPolicy_HubRegionDiscovery_EndToEnd_DirectMode()
596596 Assert . AreEqual ( bool . TrueString , headerValues [ 0 ] , "Hub region header value should remain 'True'." ) ;
597597 }
598598
599+ /// <summary>
600+ /// Verifies that once the hub region header is set (after two consecutive 404/1002),
601+ /// it persists through subsequent retries triggered by other retriable errors
602+ /// (503 ServiceUnavailable, 408 RequestTimeout) and that the normal preferred-region
603+ /// cycling continues with the header attached.
604+ /// </summary>
605+ [ TestMethod ]
606+ public async Task ClientRetryPolicy_HubRegionHeader_PersistsThroughRetriableErrors ( )
607+ {
608+ const bool enableEndpointDiscovery = true ;
609+
610+ using GlobalEndpointManager endpointManager = this . Initialize (
611+ useMultipleWriteLocations : false ,
612+ enableEndpointDiscovery : enableEndpointDiscovery ,
613+ isPreferredLocationsListEmpty : false ,
614+ enforceSingleMasterSingleWriteLocation : true ) ;
615+
616+ ClientRetryPolicy retryPolicy = new ClientRetryPolicy (
617+ endpointManager ,
618+ this . partitionKeyRangeLocationCache ,
619+ new RetryOptions ( ) ,
620+ enableEndpointDiscovery ,
621+ isThinClientEnabled : false ) ;
622+
623+ DocumentServiceRequest request = this . CreateRequest ( isReadRequest : true , isMasterResourceType : false ) ;
624+
625+ // ---- 1st 404/1002 ----
626+ retryPolicy . OnBeforeSendRequest ( request ) ;
627+ ShouldRetryResult shouldRetry = await retryPolicy . ShouldRetryAsync (
628+ new DocumentClientException (
629+ message : "1st 404/1002" ,
630+ innerException : null ,
631+ statusCode : HttpStatusCode . NotFound ,
632+ substatusCode : SubStatusCodes . ReadSessionNotAvailable ,
633+ requestUri : request . RequestContext . LocationEndpointToRoute ,
634+ responseHeaders : new DictionaryNameValueCollection ( ) ) ,
635+ CancellationToken . None ) ;
636+ Assert . IsTrue ( shouldRetry . ShouldRetry ) ;
637+
638+ // ---- 2nd 404/1002 → hub header flag gets set ----
639+ retryPolicy . OnBeforeSendRequest ( request ) ;
640+ shouldRetry = await retryPolicy . ShouldRetryAsync (
641+ new DocumentClientException (
642+ message : "2nd 404/1002" ,
643+ innerException : null ,
644+ statusCode : HttpStatusCode . NotFound ,
645+ substatusCode : SubStatusCodes . ReadSessionNotAvailable ,
646+ requestUri : request . RequestContext . LocationEndpointToRoute ,
647+ responseHeaders : new DictionaryNameValueCollection ( ) ) ,
648+ CancellationToken . None ) ;
649+ Assert . IsTrue ( shouldRetry . ShouldRetry , "Should retry so the hub header can be sent." ) ;
650+
651+ // ---- 3rd request: hub header should be present ----
652+ retryPolicy . OnBeforeSendRequest ( request ) ;
653+ string [ ] headerValues = request . Headers . GetValues ( HubRegionHeader ) ;
654+ Assert . IsNotNull ( headerValues , "Hub region header must be present after two 404/1002 failures." ) ;
655+ Assert . AreEqual ( bool . TrueString , headerValues [ 0 ] ) ;
656+
657+ // ---- Now simulate a retriable 503 ServiceUnavailable error ----
658+ shouldRetry = await retryPolicy . ShouldRetryAsync (
659+ new DocumentClientException (
660+ message : "503 ServiceUnavailable after hub header set" ,
661+ innerException : null ,
662+ statusCode : HttpStatusCode . ServiceUnavailable ,
663+ substatusCode : SubStatusCodes . Unknown ,
664+ requestUri : request . RequestContext . LocationEndpointToRoute ,
665+ responseHeaders : new DictionaryNameValueCollection ( ) ) ,
666+ CancellationToken . None ) ;
667+ Assert . IsTrue ( shouldRetry . ShouldRetry , "Should retry on 503 ServiceUnavailable." ) ;
668+
669+ // ---- 4th request: hub header must STILL be present after 503 retry ----
670+ retryPolicy . OnBeforeSendRequest ( request ) ;
671+ headerValues = request . Headers . GetValues ( HubRegionHeader ) ;
672+ Assert . IsNotNull ( headerValues , "Hub region header must persist through 503 retry." ) ;
673+ Assert . AreEqual ( bool . TrueString , headerValues [ 0 ] , "Hub region header value should remain 'True'." ) ;
674+ }
675+
599676 private async Task ValidateConnectTimeoutTriggersClientRetryPolicyAsync (
600677 bool isReadRequest ,
601678 bool useMultipleWriteLocations ,
0 commit comments