Create new observation context for WebClient retries

Prior to this commit, the `DefaultWebClient` observability
instrumentation would create the observation context before the reactive
pipeline is fully materialized. In case of errors and retries (with the
`retry(long)` operator), the observation context would be reused for
separate observations, which is incorrect.

This commit ensures that a new observation context is created for each
subscription.

Fixes gh-34671
This commit is contained in:
Brian Clozel
2025-04-02 09:37:16 +02:00
parent c4e25a1162
commit b8158df3d6
2 changed files with 27 additions and 10 deletions

View File

@@ -69,6 +69,7 @@ class WebClientObservationTests {
when(mockResponse.statusCode()).thenReturn(HttpStatus.OK);
when(mockResponse.headers()).thenReturn(new MockClientHeaders());
when(mockResponse.bodyToMono(Void.class)).thenReturn(Mono.empty());
when(mockResponse.bodyToMono(String.class)).thenReturn(Mono.error(IllegalStateException::new), Mono.just("Hello"));
when(mockResponse.bodyToFlux(String.class)).thenReturn(Flux.just("first", "second"));
when(mockResponse.releaseBody()).thenReturn(Mono.empty());
when(this.exchangeFunction.exchange(this.request.capture())).thenReturn(Mono.just(mockResponse));
@@ -141,6 +142,16 @@ class WebClientObservationTests {
.hasLowCardinalityKeyValue("status", "200");
}
@Test
void recordsSingleObservationForRetries() {
StepVerifier.create(this.builder.build().get().uri("/path").retrieve().bodyToMono(String.class).retry(1))
.expectNextCount(1)
.expectComplete()
.verify(Duration.ofSeconds(2));
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
.hasLowCardinalityKeyValue("status", "200");
}
@Test
void setsCurrentObservationInReactorContext() {
ExchangeFilterFunction assertionFilter = (request, chain) -> chain.exchange(request).contextWrite(context -> {