Skip to content

Commit a787088

Browse files
committed
Merge branch '6.2.x'
2 parents 533283a + b8158df commit a787088

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

Diff for: spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java

+15-9
Original file line numberDiff line numberDiff line change
@@ -436,22 +436,23 @@ public <V> Flux<V> exchangeToFlux(Function<ClientResponse, ? extends Flux<V>> re
436436

437437
private Mono<ClientResponse> exchange() {
438438
ClientRequest.Builder requestBuilder = initRequestBuilder();
439-
ClientRequestObservationContext observationContext = new ClientRequestObservationContext(requestBuilder);
440439
return Mono.deferContextual(contextView -> {
441440
Observation observation = ClientHttpObservationDocumentation.HTTP_REACTIVE_CLIENT_EXCHANGES.observation(observationConvention,
442-
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, observationRegistry);
441+
DEFAULT_OBSERVATION_CONVENTION, () -> new ClientRequestObservationContext(requestBuilder), observationRegistry);
443442
observation
444443
.parentObservation(contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null))
445444
.start();
446-
ExchangeFilterFunction filterFunction = new ObservationFilterFunction(observationContext);
445+
ExchangeFilterFunction filterFunction = new ObservationFilterFunction(observation.getContext());
447446
if (filterFunctions != null) {
448447
filterFunction = filterFunctions.andThen(filterFunction);
449448
}
450449
contextView.getOrEmpty(COROUTINE_CONTEXT_ATTRIBUTE)
451450
.ifPresent(context -> requestBuilder.attribute(COROUTINE_CONTEXT_ATTRIBUTE, context));
452451
ClientRequest request = requestBuilder.build();
453-
observationContext.setUriTemplate((String) request.attribute(URI_TEMPLATE_ATTRIBUTE).orElse(null));
454-
observationContext.setRequest(request);
452+
if (observation.getContext() instanceof ClientRequestObservationContext observationContext) {
453+
observationContext.setUriTemplate((String) request.attribute(URI_TEMPLATE_ATTRIBUTE).orElse(null));
454+
observationContext.setRequest(request);
455+
}
455456
final ExchangeFilterFunction finalFilterFunction = filterFunction;
456457
Mono<ClientResponse> responseMono = Mono.defer(
457458
() -> finalFilterFunction.apply(exchangeFunction).exchange(request))
@@ -464,7 +465,8 @@ private Mono<ClientResponse> exchange() {
464465
.doOnNext(response -> responseReceived.set(true))
465466
.doOnError(observation::error)
466467
.doFinally(signalType -> {
467-
if (signalType == SignalType.CANCEL && !responseReceived.get()) {
468+
if (signalType == SignalType.CANCEL && !responseReceived.get() &&
469+
observation.getContext() instanceof ClientRequestObservationContext observationContext) {
468470
observationContext.setAborted(true);
469471
}
470472
observation.stop();
@@ -728,15 +730,19 @@ public Mono<? extends Throwable> apply(ClientResponse response) {
728730

729731
private static class ObservationFilterFunction implements ExchangeFilterFunction {
730732

731-
private final ClientRequestObservationContext observationContext;
733+
private final Observation.Context observationContext;
732734

733-
ObservationFilterFunction(ClientRequestObservationContext observationContext) {
735+
ObservationFilterFunction(Observation.Context observationContext) {
734736
this.observationContext = observationContext;
735737
}
736738

737739
@Override
738740
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
739-
return next.exchange(request).doOnNext(this.observationContext::setResponse);
741+
Mono<ClientResponse> exchange = next.exchange(request);
742+
if (this.observationContext instanceof ClientRequestObservationContext clientContext) {
743+
exchange = exchange.doOnNext(clientContext::setResponse);
744+
}
745+
return exchange;
740746
}
741747
}
742748

Diff for: spring-webflux/src/test/java/org/springframework/web/reactive/function/client/WebClientObservationTests.java

+11
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ void setup() {
6969
when(mockResponse.statusCode()).thenReturn(HttpStatus.OK);
7070
when(mockResponse.headers()).thenReturn(new MockClientHeaders());
7171
when(mockResponse.bodyToMono(Void.class)).thenReturn(Mono.empty());
72+
when(mockResponse.bodyToMono(String.class)).thenReturn(Mono.error(IllegalStateException::new), Mono.just("Hello"));
7273
when(mockResponse.bodyToFlux(String.class)).thenReturn(Flux.just("first", "second"));
7374
when(mockResponse.releaseBody()).thenReturn(Mono.empty());
7475
when(this.exchangeFunction.exchange(this.request.capture())).thenReturn(Mono.just(mockResponse));
@@ -141,6 +142,16 @@ void recordsObservationForCancelledExchangeDuringResponse() {
141142
.hasLowCardinalityKeyValue("status", "200");
142143
}
143144

145+
@Test
146+
void recordsSingleObservationForRetries() {
147+
StepVerifier.create(this.builder.build().get().uri("/path").retrieve().bodyToMono(String.class).retry(1))
148+
.expectNextCount(1)
149+
.expectComplete()
150+
.verify(Duration.ofSeconds(2));
151+
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
152+
.hasLowCardinalityKeyValue("status", "200");
153+
}
154+
144155
@Test
145156
void setsCurrentObservationInReactorContext() {
146157
ExchangeFilterFunction assertionFilter = (request, chain) -> chain.exchange(request).contextWrite(context -> {

0 commit comments

Comments
 (0)