差異處
這裏顯示兩個版本的差異處。
Both sides previous revision 前次修改 下次修改 | 前次修改 | ||
java:web:resteasy:invalid_connection_request_timeout [2018/05/28 00:02] tony |
java:web:resteasy:invalid_connection_request_timeout [2023/06/25 09:48] (目前版本) |
||
---|---|---|---|
行 1: | 行 1: | ||
- | ====== Connection Pool的Request Timeout沒有作用 (working..) ====== | + | {{tag>resteasy httpclient}} |
+ | ====== RESTEasy - Connection Pool的Request Timeout沒有作用 ====== | ||
===== Problem ===== | ===== Problem ===== | ||
- | RestAPI的開發者,大都會非常頻繁的存取目標機器;Connection Pool是其中一個增進存取效率的方式。然而,這陣子在使用RESTEasy + Apache Connection Pool後,發現ConnectionRequestTimeout並沒作用。本篇文章主要分享目前的解決方法。 | + | REST API的開發者,大都會非常頻繁的存取REST服務提供者;Connection Pool是其中一個增進存取效率的方式。然而,這陣子在使用RESTEasy + Apache Connection Pool後,發現ConnectionRequestTimeout並沒作用。本篇文章主要分享目前的解決方法。 |
===== Version Info ===== | ===== Version Info ===== | ||
- | 因為相依libraries的限制,我們目前還沒使用最新版本的RESTEasy,資訊如下: | + | 由於某些限制,我們目前還沒使用最新版本的RESTEasy,版本資訊如下: |
<code> | <code> | ||
resteasy-client: 3.0.14.Final | resteasy-client: 3.0.14.Final | ||
行 42: | 行 43: | ||
clientBuilder.httpEngine(httpEngin); | clientBuilder.httpEngine(httpEngin); | ||
// 以下略 | // 以下略 | ||
+ | </code> | ||
+ | 接著是發出兩個請求,第一個請求沒執行close,接著執行第二個請求: | ||
+ | <code java> | ||
+ | // 延續httpEngine的初始化 | ||
+ | Client client = clientBuilder.build(); | ||
+ | |||
+ | Response leak_repsonse = client.target(target).request().get(); | ||
+ | Response second_response = null; | ||
+ | |||
+ | long before = System.currentTimeMillis(); | ||
+ | try { | ||
+ | second_response = client.target(target).request().get(); | ||
+ | fail("should be timeout"); | ||
+ | } catch (Exception e) { | ||
+ | assertNotNull(e.getCause()); | ||
+ | assertTrue(e.getCause() instanceof ConnectionPoolTimeoutException); | ||
+ | assertEquals(expectTimeout, System.currentTimeMillis() - before, 500); | ||
+ | } finally { | ||
+ | leak_repsonse.close(); | ||
+ | if( second_response != null ) | ||
+ | second_response.close(); | ||
+ | } | ||
} | } | ||
</code> | </code> | ||
+ | 在執行以上測試後,會因為第二個請求block直到Test case 20秒timeout而錯誤;此測試並沒發生預期的ConnectionPoolTimeoutException。 | ||
+ | ===== Test HttpClient ===== | ||
+ | 由於前一個測試沒達到預期效果,因此繼續確認PoolingHttpClientConnectionManager是否有問題。測試流程與前一個測試大同小異,差別只在於是直接對HttpClient做操作: | ||
+ | <code java> | ||
+ | @Test(timeout=20*1000) | ||
+ | public void testRequestTimeout() throws Exception { | ||
+ | int expect_timeout = 2*1000; | ||
+ | connectionManager = new HttpClientConnectionManagerBuilder().build(); | ||
+ | RequestConfig requestConfig = RequestConfig.custom() | ||
+ | .setConnectionRequestTimeout(expect_timeout) | ||
+ | .build(); | ||
+ | |||
+ | HttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager) | ||
+ | .setDefaultRequestConfig(requestConfig) | ||
+ | .build(); | ||
+ | |||
+ | HttpUriRequest uriRequest = new HttpGet(target); | ||
+ | HttpResponse response = httpClient.execute(uriRequest); | ||
+ | assertEquals(200, response.getStatusLine().getStatusCode()); | ||
+ | long before = System.currentTimeMillis(); | ||
+ | try { | ||
+ | uriRequest = new HttpGet(target); | ||
+ | response = httpClient.execute(uriRequest); | ||
+ | } catch( ConnectionPoolTimeoutException e ) { | ||
+ | assertEquals("Timeout waiting for connection from pool", e.getMessage()); | ||
+ | } | ||
+ | long duration = System.currentTimeMillis() - before; | ||
+ | assertEquals(expect_timeout, duration, 500); | ||
+ | } | ||
+ | </code> | ||
+ | 這個測試最後會因為第二個連線無法在2秒內取得而拋出ConnectionPoolTimeoutException。 | ||
+ | ===== How to fix? ===== | ||
+ | 根據這兩個測試,懷疑是RESTEasy與HttpClient整合起來的問題。測試過更新RESTEasy與HttpClient的libraries後,確認只要將HttpClient的library升級至4.5.3以上就可以解決問題: | ||
+ | <code> | ||
+ | resteasy-client: 3.0.14.Final | ||
+ | httpcore: 4.3.3 | ||
+ | httpclient: 4.5.3 | ||
+ | </code> | ||
+ | ===== ===== | ||
+ | ---- | ||
+ | \\ | ||
+ | ~~DISQUS~~ |