Skip to content

Commit 3abc5d6

Browse files
authored
Merge pull request #1722 from ClickHouse/feat_check_connection_before_use
Added ClickHouseHttpOption AHC_VALIDATE_AFTER_INACTIVITY to control connection validation
2 parents 247f322 + cfe6c2e commit 3abc5d6

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

clickhouse-http-client/src/main/java/com/clickhouse/client/http/ApacheHttpConnectionImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ public HttpConnectionManager(Registry<ConnectionSocketFactory> socketFactory, Cl
376376

377377
ConnectionConfig connConfig = ConnectionConfig.custom()
378378
.setConnectTimeout(Timeout.of(config.getConnectionTimeout(), TimeUnit.MILLISECONDS))
379+
.setValidateAfterInactivity(config.getLongOption(ClickHouseHttpOption.AHC_VALIDATE_AFTER_INACTIVITY), TimeUnit.MILLISECONDS)
379380
.build();
380381
setDefaultConnectionConfig(connConfig);
381382

clickhouse-http-client/src/main/java/com/clickhouse/client/http/config/ClickHouseHttpOption.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,16 @@ public enum ClickHouseHttpOption implements ClickHouseOption {
6464
* Only one role can be set at a time.
6565
*/
6666
REMEMBER_LAST_SET_ROLES("remember_last_set_roles", false,
67-
"Whether to remember last set role and send them in every next requests as query parameters.");
67+
"Whether to remember last set role and send them in every next requests as query parameters."),
68+
69+
/**
70+
* The time in milliseconds after which the connection is validated after inactivity.
71+
* Default value is 5000 ms. If set to negative value, the connection is never validated.
72+
* It is used only for Apache Http Client connection provider.
73+
*/
74+
AHC_VALIDATE_AFTER_INACTIVITY("ahc_validate_after_inactivity", 5000L,
75+
"The time in milliseconds after which the connection is validated after inactivity."),
76+
;
6877

6978
private final String key;
7079
private final Serializable defaultValue;

clickhouse-http-client/src/test/java/com/clickhouse/client/http/ApacheHttpConnectionImplTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import java.io.IOException;
1818
import java.io.Serializable;
19+
import java.net.ConnectException;
1920
import java.util.Collections;
2021
import java.util.HashMap;
2122
import java.util.List;
@@ -25,9 +26,13 @@
2526

2627
import com.github.tomakehurst.wiremock.WireMockServer;
2728
import com.github.tomakehurst.wiremock.client.WireMock;
29+
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
2830
import com.github.tomakehurst.wiremock.http.Fault;
31+
import com.github.tomakehurst.wiremock.stubbing.Scenario;
2932
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
33+
import org.apache.hc.core5.http.NoHttpResponseException;
3034
import org.testng.Assert;
35+
import org.testng.annotations.DataProvider;
3136
import org.testng.annotations.Test;
3237

3338
public class ApacheHttpConnectionImplTest extends ClickHouseHttpClientTest {
@@ -144,4 +149,63 @@ public void testFailureWhileRequest() {
144149
faultyServer.stop();
145150
}
146151
}
152+
153+
@Test(groups = {"unit"}, dataProvider = "validationTimeoutProvider")
154+
public void testNoHttpResponseExceptionWithValidation(long validationTimeout) {
155+
156+
faultyServer = new WireMockServer(9090);
157+
faultyServer.start();
158+
159+
faultyServer.addStubMapping(WireMock.post(WireMock.anyUrl())
160+
.inScenario("validateOnStaleConnection")
161+
.withRequestBody(WireMock.equalTo("SELECT 100"))
162+
.willReturn(WireMock.aResponse()
163+
.withHeader("X-ClickHouse-Summary",
164+
"{ \"read_bytes\": \"10\", \"read_rows\": \"1\"}"))
165+
.build());
166+
167+
168+
ClickHouseHttpClient httpClient = new ClickHouseHttpClient();
169+
Map<ClickHouseOption, Serializable> options = new HashMap<>();
170+
options.put(ClickHouseHttpOption.AHC_VALIDATE_AFTER_INACTIVITY, validationTimeout);
171+
options.put(ClickHouseHttpOption.MAX_OPEN_CONNECTIONS, 1);
172+
ClickHouseConfig config = new ClickHouseConfig(options);
173+
httpClient.init(config);
174+
ClickHouseRequest request = httpClient.read("http://localhost:9090/").query("SELECT 100");
175+
176+
Runnable powerBlink = () -> {
177+
try {
178+
Thread.sleep(100);
179+
faultyServer.stop();
180+
Thread.sleep(50);
181+
faultyServer.start();
182+
} catch (InterruptedException e) {
183+
Assert.fail("Unexpected exception", e);
184+
}
185+
};
186+
try {
187+
ClickHouseResponse response = httpClient.executeAndWait(request);
188+
Assert.assertEquals(response.getSummary().getReadRows(), 1);
189+
response.close();
190+
new Thread(powerBlink).start();
191+
Thread.sleep(200);
192+
response = httpClient.executeAndWait(request);
193+
Assert.assertEquals(response.getSummary().getReadRows(), 1);
194+
response.close();
195+
} catch (Exception e) {
196+
if (validationTimeout < 0) {
197+
Assert.assertTrue(e instanceof ClickHouseException);
198+
Assert.assertTrue(e.getCause() instanceof ConnectException);
199+
} else {
200+
Assert.fail("Unexpected exception", e);
201+
}
202+
} finally {
203+
faultyServer.stop();
204+
}
205+
}
206+
207+
@DataProvider(name = "validationTimeoutProvider")
208+
public static Object[] validationTimeoutProvider() {
209+
return new Long[] {-1L , 100L };
210+
}
147211
}

0 commit comments

Comments
 (0)