This is an automated email from the ASF dual-hosted git repository.

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 86196af675 fix(sdk): preserve retryable http client failures (#7072)
86196af675 is described below

commit 86196af6755a50c67f2b581b81e56be62ec1de24
Author: Liming Deng <[email protected]>
AuthorDate: Wed Sep 30 09:56:47 2026 +0800

    fix(sdk): preserve retryable http client failures (#7072)
    
    * fix(sdk): preserve retryable http client failures
    
    * test(sdk): cover cancelled http requests
---
 .../shenyu/sdk/httpclient/HttpShenyuSdkClient.java | 35 +++++++++---
 .../sdk/httpclient/HttpShenyuSdkClientTest.java    | 64 ++++++++++++++++++++++
 2 files changed, 92 insertions(+), 7 deletions(-)

diff --git 
a/shenyu-sdk/shenyu-sdk-httpclient/src/main/java/org/apache/shenyu/sdk/httpclient/HttpShenyuSdkClient.java
 
b/shenyu-sdk/shenyu-sdk-httpclient/src/main/java/org/apache/shenyu/sdk/httpclient/HttpShenyuSdkClient.java
index 17125d305e..32dfbc29fc 100644
--- 
a/shenyu-sdk/shenyu-sdk-httpclient/src/main/java/org/apache/shenyu/sdk/httpclient/HttpShenyuSdkClient.java
+++ 
b/shenyu-sdk/shenyu-sdk-httpclient/src/main/java/org/apache/shenyu/sdk/httpclient/HttpShenyuSdkClient.java
@@ -52,6 +52,8 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.stream.Collectors;
 
@@ -162,14 +164,33 @@ public class HttpShenyuSdkClient extends 
AbstractShenyuSdkClient {
                 LOG.debug("HttpResponse cancelled.");
             }
         });
+        HttpResponse response = waitForResponse(execute);
+        return new ShenyuResponse(response.getStatusLine().getStatusCode(), 
response.getStatusLine().getReasonPhrase(),
+                
Arrays.stream(response.getAllHeaders()).collect(Collectors.groupingBy(Header::getName,
 HashMap::new,
+                        Collectors.mapping(Header::getValue, 
Collectors.toCollection(LinkedList::new)))),
+                EntityUtils.toString(response.getEntity(), 
StandardCharsets.UTF_8), request);
+    }
+
+    private HttpResponse waitForResponse(final Future<HttpResponse> 
responseFuture) throws IOException {
         try {
-            HttpResponse response = execute.get();
-            return new 
ShenyuResponse(response.getStatusLine().getStatusCode(), 
response.getStatusLine().getReasonPhrase(),
-                    
Arrays.stream(response.getAllHeaders()).collect(Collectors.groupingBy(Header::getName,
 HashMap::new,
-                            Collectors.mapping(Header::getValue, 
Collectors.toCollection(LinkedList::new)))),
-                    EntityUtils.toString(response.getEntity(), 
StandardCharsets.UTF_8), request);
-        } catch (Exception e) {
-            throw new ShenyuException(e);
+            return responseFuture.get();
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new IOException("Interrupted while waiting for the HTTP 
response", e);
+        } catch (ExecutionException e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof IOException) {
+                throw (IOException) cause;
+            }
+            if (cause instanceof RuntimeException) {
+                throw (RuntimeException) cause;
+            }
+            if (cause instanceof Error) {
+                throw (Error) cause;
+            }
+            throw new IOException("HTTP request failed", cause);
+        } catch (CancellationException e) {
+            throw new IOException("HTTP request was cancelled", e);
         }
     }
 
diff --git 
a/shenyu-sdk/shenyu-sdk-httpclient/src/test/java/org/apache/shenyu/sdk/httpclient/HttpShenyuSdkClientTest.java
 
b/shenyu-sdk/shenyu-sdk-httpclient/src/test/java/org/apache/shenyu/sdk/httpclient/HttpShenyuSdkClientTest.java
index a77e194adf..07d116109f 100644
--- 
a/shenyu-sdk/shenyu-sdk-httpclient/src/test/java/org/apache/shenyu/sdk/httpclient/HttpShenyuSdkClientTest.java
+++ 
b/shenyu-sdk/shenyu-sdk-httpclient/src/test/java/org/apache/shenyu/sdk/httpclient/HttpShenyuSdkClientTest.java
@@ -17,16 +17,25 @@
 
 package org.apache.shenyu.sdk.httpclient;
 
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.concurrent.FutureCallback;
+import org.apache.http.nio.client.HttpAsyncClient;
 import org.apache.shenyu.sdk.core.ShenyuRequest;
+import org.junit.Assert;
 import org.junit.Test;
 import org.mockito.Mockito;
 
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -44,4 +53,59 @@ public class HttpShenyuSdkClientTest {
         when(shenyuHttpClient.doRequest(shenyuRequest)).thenCallRealMethod();
     }
 
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testTransportFailureThrowsIOException() throws Exception {
+        HttpShenyuSdkClient shenyuHttpClient = new HttpShenyuSdkClient();
+        HttpAsyncClient httpAsyncClient = mock(HttpAsyncClient.class);
+        Future<HttpResponse> future = mock(Future.class);
+        when(httpAsyncClient.execute(Mockito.any(HttpUriRequest.class), 
Mockito.<FutureCallback<HttpResponse>>any())).thenReturn(future);
+        when(future.get()).thenThrow(new ExecutionException(new 
IOException("connection reset")));
+        setHttpAsyncClient(shenyuHttpClient, httpAsyncClient);
+
+        Assert.assertThrows(IOException.class, () -> 
shenyuHttpClient.doRequest(createRequest()));
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testInterruptedFailureRestoresInterruptStatus() throws 
Exception {
+        HttpShenyuSdkClient shenyuHttpClient = new HttpShenyuSdkClient();
+        HttpAsyncClient httpAsyncClient = mock(HttpAsyncClient.class);
+        Future<HttpResponse> future = mock(Future.class);
+        when(httpAsyncClient.execute(Mockito.any(HttpUriRequest.class), 
Mockito.<FutureCallback<HttpResponse>>any())).thenReturn(future);
+        when(future.get()).thenThrow(new InterruptedException("interrupted"));
+        setHttpAsyncClient(shenyuHttpClient, httpAsyncClient);
+
+        try {
+            Assert.assertThrows(IOException.class, () -> 
shenyuHttpClient.doRequest(createRequest()));
+            Assert.assertTrue(Thread.currentThread().isInterrupted());
+        } finally {
+            Thread.interrupted();
+        }
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testCancelledRequestThrowsIOException() throws Exception {
+        HttpShenyuSdkClient shenyuHttpClient = new HttpShenyuSdkClient();
+        HttpAsyncClient httpAsyncClient = mock(HttpAsyncClient.class);
+        Future<HttpResponse> future = mock(Future.class);
+        when(httpAsyncClient.execute(Mockito.any(HttpUriRequest.class), 
Mockito.<FutureCallback<HttpResponse>>any())).thenReturn(future);
+        when(future.get()).thenThrow(new CancellationException("cancelled"));
+        setHttpAsyncClient(shenyuHttpClient, httpAsyncClient);
+
+        Assert.assertThrows(IOException.class, () -> 
shenyuHttpClient.doRequest(createRequest()));
+    }
+
+    private ShenyuRequest createRequest() {
+        return ShenyuRequest.create(ShenyuRequest.HttpMethod.GET, 
"http://localhost/test";,
+                new HashMap<>(), null, null, null);
+    }
+
+    private void setHttpAsyncClient(final HttpShenyuSdkClient client, final 
HttpAsyncClient httpAsyncClient) throws Exception {
+        Field field = 
HttpShenyuSdkClient.class.getDeclaredField("httpAsyncClient");
+        field.setAccessible(true);
+        field.set(client, httpAsyncClient);
+    }
+
 }

Reply via email to