差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

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~~