log and return empty mono when WebClient request fails sending zipkin trace data (#2170)

* log and return empty mono when WebClient request fails sending zipkin trace data

* updated tests and RestTemplateSender to handle exceptions

* removed unused imports

* added the option to send in a custom doOnError function

* removed unused loggers

* added the option to send in a custom wrapper function which can customize the reactive flow

* updated javadoc

* updated javadoc
This commit is contained in:
Jarle Hansen
2022-05-27 12:16:18 +02:00
committed by GitHub
parent 2ab357a4c7
commit a91a9f8c86
2 changed files with 48 additions and 6 deletions

View File

@@ -18,12 +18,15 @@ package org.springframework.cloud.sleuth.zipkin2;
import java.net.URI;
import java.time.Duration;
import java.util.function.Function;
import reactor.core.publisher.Mono;
import zipkin2.Span;
import zipkin2.codec.BytesEncoder;
import zipkin2.reporter.Sender;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.reactive.function.client.WebClient;
/**
@@ -47,7 +50,7 @@ public class WebClientSender extends HttpSender {
*/
@Deprecated
public WebClientSender(WebClient webClient, String baseUrl, String apiPath, BytesEncoder<Span> encoder) {
this(webClient, baseUrl, apiPath, encoder, DEFAULT_CHECK_TIMEOUT);
this(null, webClient, baseUrl, apiPath, encoder, DEFAULT_CHECK_TIMEOUT);
}
/**
@@ -60,13 +63,35 @@ public class WebClientSender extends HttpSender {
*/
public WebClientSender(WebClient webClient, String baseUrl, String apiPath, BytesEncoder<Span> encoder,
long checkTimeout) {
super((url, mediaType, bytes) -> post(url, mediaType, bytes, webClient, checkTimeout), baseUrl, apiPath,
encoder);
super((url, mediaType, bytes) -> post(null, url, mediaType, bytes, webClient, checkTimeout).block(), baseUrl,
apiPath, encoder);
}
private static void post(String url, MediaType mediaType, byte[] json, WebClient webClient, long checkTimeout) {
webClient.post().uri(URI.create(url)).accept(mediaType).contentType(mediaType).bodyValue(json).retrieve()
.toBodilessEntity().timeout(Duration.ofMillis(checkTimeout)).block();
/**
* Creates a new instance of {@link WebClientSender}.
* @param webClient web client
* @param wrapperFunction function that will be run on onErrorResume. Send in null to
* get default behavior.
* @param baseUrl base url
* @param apiPath api path
* @param encoder encoder
* @param checkTimeout check timeout
*/
public WebClientSender(Function<Mono<ResponseEntity<Void>>, Mono<ResponseEntity<Void>>> wrapperFunction,
WebClient webClient, String baseUrl, String apiPath, BytesEncoder<Span> encoder, long checkTimeout) {
super((url, mediaType, bytes) -> post(wrapperFunction, url, mediaType, bytes, webClient, checkTimeout).block(),
baseUrl, apiPath, encoder);
}
private static Mono<ResponseEntity<Void>> post(
Function<Mono<ResponseEntity<Void>>, Mono<ResponseEntity<Void>>> wrapperFunction, String url,
MediaType mediaType, byte[] json, WebClient webClient, long checkTimeout) {
if (wrapperFunction == null) {
wrapperFunction = (response) -> response;
}
return wrapperFunction.apply(webClient.post().uri(URI.create(url)).accept(mediaType).contentType(mediaType)
.bodyValue(json).retrieve().toBodilessEntity().timeout(Duration.ofMillis(checkTimeout)));
}
@Override

View File

@@ -16,11 +16,17 @@
package org.springframework.cloud.sleuth.zipkin2;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import zipkin2.CheckResult;
import zipkin2.reporter.Sender;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import static org.assertj.core.api.Assertions.assertThat;
import static zipkin2.codec.SpanBytesEncoder.JSON_V2;
import static zipkin2.codec.SpanBytesEncoder.PROTO3;
@@ -59,4 +65,15 @@ class WebClientSenderTests extends AbstractSenderTest {
return "WebClientSender{" + this.endpoint + mockedApiPath + "}";
}
@Test
void customFunctionToResumeAfterError() throws IOException {
WebClientSender sender = new WebClientSender((response) -> response.onErrorResume((error) -> Mono.empty()),
WebClient.builder().clientConnector(new ReactorClientHttpConnector()).build(), this.endpoint, "",
PROTO3, DEFAULT_CHECK_TIMEOUT);
this.server.shutdown();
CheckResult result = sender.check();
assertThat(result.ok()).isTrue();
}
}