77import java .net .http .HttpRequest .BodyPublishers ;
88import java .net .http .HttpRequest .Builder ;
99import java .net .http .HttpResponse ;
10- import java .util .*;
10+ import java .time .Duration ;
11+ import java .util .ArrayList ;
12+ import java .util .Arrays ;
13+ import java .util .List ;
14+ import java .util .Map ;
15+ import java .util .Properties ;
1116import java .util .concurrent .CompletableFuture ;
17+ import java .util .concurrent .ExecutorService ;
18+ import java .util .concurrent .Executors ;
1219import java .util .stream .Collectors ;
1320
1421import lombok .extern .slf4j .Slf4j ;
1522import org .apache .flink .annotation .VisibleForTesting ;
23+ import org .apache .flink .util .concurrent .ExecutorThreadFactory ;
1624
1725import com .getindata .connectors .http .HttpPostRequestCallback ;
1826import com .getindata .connectors .http .internal .HeaderPreprocessor ;
2634import com .getindata .connectors .http .internal .table .sink .Slf4jHttpPostRequestCallback ;
2735import com .getindata .connectors .http .internal .utils .HttpHeaderUtils ;
2836import com .getindata .connectors .http .internal .utils .JavaNetHttpClientFactory ;
37+ import com .getindata .connectors .http .internal .utils .ThreadUtils ;
2938
3039/**
31- * An implementation of {@link SinkHttpClient} that uses Java 11's {@link HttpClient}.
32- * This implementation supports HTTP traffic only.
40+ * An implementation of {@link SinkHttpClient} that uses Java 11's {@link HttpClient}. This
41+ * implementation supports HTTP traffic only.
3342 */
3443@ Slf4j
3544public class JavaNetSinkHttpClient implements SinkHttpClient {
3645
46+ private static final int HTTP_CLIENT_THREAD_POOL_SIZE = 16 ;
47+
48+ public static final String DEFAULT_REQUEST_TIMEOUT_SECONDS = "30" ;
49+
3750 private final HttpClient httpClient ;
3851
3952 private final String [] headersAndValues ;
@@ -44,16 +57,29 @@ public class JavaNetSinkHttpClient implements SinkHttpClient {
4457
4558 private final HttpPostRequestCallback <HttpSinkRequestEntry > httpPostRequestCallback ;
4659
60+ /**
61+ * Thread pool to handle HTTP response from HTTP client.
62+ */
63+ private final ExecutorService publishingThreadPool ;
64+
65+ private final int httpRequestTimeOutSeconds ;
66+
4767 public JavaNetSinkHttpClient (Properties properties , HeaderPreprocessor headerPreprocessor ) {
4868 this (properties , new Slf4jHttpPostRequestCallback (), headerPreprocessor );
4969 }
5070
5171 public JavaNetSinkHttpClient (
52- Properties properties ,
53- HttpPostRequestCallback <HttpSinkRequestEntry > httpPostRequestCallback ,
54- HeaderPreprocessor headerPreprocessor ) {
72+ Properties properties ,
73+ HttpPostRequestCallback <HttpSinkRequestEntry > httpPostRequestCallback ,
74+ HeaderPreprocessor headerPreprocessor ) {
5575
56- this .httpClient = JavaNetHttpClientFactory .createClient (properties );
76+ ExecutorService httpClientExecutor =
77+ Executors .newFixedThreadPool (
78+ HTTP_CLIENT_THREAD_POOL_SIZE ,
79+ new ExecutorThreadFactory (
80+ "http-sink-client-request-worker" , ThreadUtils .LOGGING_EXCEPTION_HANDLER ));
81+
82+ this .httpClient = JavaNetHttpClientFactory .createClient (properties , httpClientExecutor );
5783 this .httpPostRequestCallback = httpPostRequestCallback ;
5884 this .headerMap = HttpHeaderUtils .prepareHeaderMap (
5985 HttpConnectorConfigConstants .SINK_HEADER_PREFIX ,
@@ -72,12 +98,23 @@ public JavaNetSinkHttpClient(
7298 .build ();
7399
74100 this .statusCodeChecker = new ComposeHttpStatusCodeChecker (checkerConfig );
101+
102+ this .publishingThreadPool =
103+ Executors .newFixedThreadPool (
104+ HTTP_CLIENT_THREAD_POOL_SIZE ,
105+ new ExecutorThreadFactory (
106+ "http-sink-client-response-worker" , ThreadUtils .LOGGING_EXCEPTION_HANDLER ));
107+
108+ this .httpRequestTimeOutSeconds = Integer .parseInt (
109+ properties .getProperty (HttpConnectorConfigConstants .SINK_HTTP_TIMEOUT_SECONDS ,
110+ DEFAULT_REQUEST_TIMEOUT_SECONDS )
111+ );
75112 }
76113
77114 @ Override
78115 public CompletableFuture <SinkHttpClientResponse > putRequests (
79- List <HttpSinkRequestEntry > requestEntries ,
80- String endpointUrl ) {
116+ List <HttpSinkRequestEntry > requestEntries ,
117+ String endpointUrl ) {
81118 return submitRequests (requestEntries , endpointUrl )
82119 .thenApply (responses -> prepareSinkHttpClientResponse (responses , endpointUrl ));
83120 }
@@ -87,6 +124,7 @@ private HttpRequest buildHttpRequest(HttpSinkRequestEntry requestEntry, URI endp
87124 .newBuilder ()
88125 .uri (endpointUri )
89126 .version (Version .HTTP_1_1 )
127+ .timeout (Duration .ofSeconds (httpRequestTimeOutSeconds ))
90128 .method (requestEntry .method ,
91129 BodyPublishers .ofByteArray (requestEntry .element ));
92130
@@ -98,20 +136,25 @@ private HttpRequest buildHttpRequest(HttpSinkRequestEntry requestEntry, URI endp
98136 }
99137
100138 private CompletableFuture <List <JavaNetHttpResponseWrapper >> submitRequests (
101- List <HttpSinkRequestEntry > requestEntries ,
102- String endpointUrl ) {
139+ List <HttpSinkRequestEntry > requestEntries ,
140+ String endpointUrl ) {
103141 var endpointUri = URI .create (endpointUrl );
104142 var responseFutures = new ArrayList <CompletableFuture <JavaNetHttpResponseWrapper >>();
105143
106144 for (var entry : requestEntries ) {
107145 var response = httpClient
108- .sendAsync (buildHttpRequest (entry , endpointUri ),
146+ .sendAsync (
147+ buildHttpRequest (entry , endpointUri ),
109148 HttpResponse .BodyHandlers .ofString ())
110149 .exceptionally (ex -> {
150+ // TODO This will be executed on a ForJoinPool Thread... refactor this someday.
111151 log .error ("Request fatally failed because of an exception" , ex );
112152 return null ;
113153 })
114- .thenApply (res -> new JavaNetHttpResponseWrapper (entry , res ));
154+ .thenApplyAsync (
155+ res -> new JavaNetHttpResponseWrapper (entry , res ),
156+ publishingThreadPool
157+ );
115158 responseFutures .add (response );
116159 }
117160
@@ -121,8 +164,8 @@ private CompletableFuture<List<JavaNetHttpResponseWrapper>> submitRequests(
121164 }
122165
123166 private SinkHttpClientResponse prepareSinkHttpClientResponse (
124- List <JavaNetHttpResponseWrapper > responses ,
125- String endpointUrl ) {
167+ List <JavaNetHttpResponseWrapper > responses ,
168+ String endpointUrl ) {
126169 var successfulResponses = new ArrayList <HttpSinkRequestEntry >();
127170 var failedResponses = new ArrayList <HttpSinkRequestEntry >();
128171
0 commit comments