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

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


The following commit(s) were added to refs/heads/master by this push:
     new 856f766b204 perf: RemoteTaskActionClient streaming deserialization. 
(#20005)
856f766b204 is described below

commit 856f766b204fab1f016f7d98da3073ef10902a61
Author: Gian Merlino <[email protected]>
AuthorDate: Fri Aug 14 10:15:27 2026 -0700

    perf: RemoteTaskActionClient streaming deserialization. (#20005)
    
    This patch switches RemoteTaskActionClient to use InputStreamResponseHandler
    rather than BytesFullResponseHandler, which enables deserialization
    to run without buffering the entire response. This is useful for actions
    with potentially large responses, such as RetrieveUsedSegmentsAction.
---
 .../common/actions/RemoteTaskActionClient.java     | 41 +++++++++++++++-------
 .../common/actions/RemoteTaskActionClientTest.java | 17 ++++-----
 2 files changed, 35 insertions(+), 23 deletions(-)

diff --git 
a/indexing-service/src/main/java/org/apache/druid/indexing/common/actions/RemoteTaskActionClient.java
 
b/indexing-service/src/main/java/org/apache/druid/indexing/common/actions/RemoteTaskActionClient.java
index 4015b99558a..9b6e8edbf72 100644
--- 
a/indexing-service/src/main/java/org/apache/druid/indexing/common/actions/RemoteTaskActionClient.java
+++ 
b/indexing-service/src/main/java/org/apache/druid/indexing/common/actions/RemoteTaskActionClient.java
@@ -19,12 +19,13 @@
 
 package org.apache.druid.indexing.common.actions;
 
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.druid.indexing.common.task.Task;
 import org.apache.druid.java.util.common.IOE;
-import org.apache.druid.java.util.common.jackson.JacksonUtils;
 import org.apache.druid.java.util.common.logger.Logger;
-import 
org.apache.druid.java.util.http.client.response.BytesFullResponseHandler;
+import 
org.apache.druid.java.util.http.client.response.InputStreamResponseHandler;
 import 
org.apache.druid.java.util.http.client.response.StringFullResponseHolder;
 import org.apache.druid.rpc.HttpResponseException;
 import org.apache.druid.rpc.RequestBuilder;
@@ -32,7 +33,6 @@ import org.apache.druid.rpc.ServiceClient;
 import org.jboss.netty.handler.codec.http.HttpMethod;
 
 import java.io.IOException;
-import java.util.Map;
 import java.util.concurrent.ExecutionException;
 
 public class RemoteTaskActionClient implements TaskActionClient
@@ -63,19 +63,17 @@ public class RemoteTaskActionClient implements 
TaskActionClient
       // We're using a ServiceClient directly here instead of OverlordClient, 
because OverlordClient does
       // not have access to the TaskAction class. (OverlordClient is in the 
druid-server package, and TaskAction
       // is in the druid-indexing-service package.)
-      final Map<String, Object> response = jsonMapper.readValue(
+      return jsonMapper.<TaskActionResponse<RetType>>readValue(
           client.request(
               new RequestBuilder(HttpMethod.POST, "/druid/indexer/v1/action")
                   .jsonContent(jsonMapper, new TaskActionHolder(task, 
taskAction)),
-              new BytesFullResponseHandler()
-          ).getContent(),
-          JacksonUtils.TYPE_REFERENCE_MAP_STRING_OBJECT
-      );
-
-      return jsonMapper.convertValue(
-          response.get("result"),
-          taskAction.getReturnTypeReference()
-      );
+              new InputStreamResponseHandler()
+          ),
+          jsonMapper.getTypeFactory().constructParametricType(
+              TaskActionResponse.class,
+              
jsonMapper.getTypeFactory().constructType(taskAction.getReturnTypeReference())
+          )
+      ).getResult();
     }
     catch (InterruptedException e) {
       Thread.currentThread().interrupt();
@@ -95,4 +93,21 @@ public class RemoteTaskActionClient implements 
TaskActionClient
       throw new IOException(e.getCause());
     }
   }
+
+  public static class TaskActionResponse<RetType>
+  {
+    private final RetType result;
+
+    @JsonCreator
+    public TaskActionResponse(@JsonProperty("result") RetType result)
+    {
+      this.result = result;
+    }
+
+    @JsonProperty
+    public RetType getResult()
+    {
+      return result;
+    }
+  }
 }
diff --git 
a/indexing-service/src/test/java/org/apache/druid/indexing/common/actions/RemoteTaskActionClientTest.java
 
b/indexing-service/src/test/java/org/apache/druid/indexing/common/actions/RemoteTaskActionClientTest.java
index a84fe68ab2b..3f77fc04a5d 100644
--- 
a/indexing-service/src/test/java/org/apache/druid/indexing/common/actions/RemoteTaskActionClientTest.java
+++ 
b/indexing-service/src/test/java/org/apache/druid/indexing/common/actions/RemoteTaskActionClientTest.java
@@ -28,8 +28,7 @@ import org.apache.druid.indexing.common.task.NoopTask;
 import org.apache.druid.indexing.common.task.Task;
 import org.apache.druid.jackson.DefaultObjectMapper;
 import org.apache.druid.java.util.common.Intervals;
-import 
org.apache.druid.java.util.http.client.response.BytesFullResponseHandler;
-import org.apache.druid.java.util.http.client.response.BytesFullResponseHolder;
+import 
org.apache.druid.java.util.http.client.response.InputStreamResponseHandler;
 import 
org.apache.druid.java.util.http.client.response.StringFullResponseHolder;
 import org.apache.druid.rpc.HttpResponseException;
 import org.apache.druid.rpc.RequestBuilder;
@@ -38,15 +37,14 @@ import org.apache.druid.rpc.ServiceClientImpl;
 import org.apache.druid.rpc.StandardRetryPolicy;
 import org.easymock.EasyMock;
 import org.jboss.netty.buffer.BigEndianHeapChannelBuffer;
-import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
 import org.jboss.netty.handler.codec.http.HttpMethod;
 import org.jboss.netty.handler.codec.http.HttpResponse;
 import org.jboss.netty.handler.codec.http.HttpResponseStatus;
-import org.jboss.netty.handler.codec.http.HttpVersion;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
@@ -81,9 +79,8 @@ public class RemoteTaskActionClientTest
     ));
     expectedResponse.put("result", expectedLocks);
 
-    final DefaultHttpResponse httpResponse = new 
DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
-    final BytesFullResponseHolder responseHolder = new 
BytesFullResponseHolder(httpResponse);
-    responseHolder.addChunk(objectMapper.writeValueAsBytes(expectedResponse));
+    final ByteArrayInputStream responseStream =
+        new 
ByteArrayInputStream(objectMapper.writeValueAsBytes(expectedResponse));
 
     final Task task = NoopTask.create();
     final LockListAction action = new LockListAction();
@@ -93,10 +90,10 @@ public class RemoteTaskActionClientTest
                     EasyMock.eq(
                         new RequestBuilder(HttpMethod.POST, 
"/druid/indexer/v1/action")
                             .jsonContent(objectMapper, new 
TaskActionHolder(task, action))),
-                    EasyMock.anyObject(BytesFullResponseHandler.class)
+                    EasyMock.anyObject(InputStreamResponseHandler.class)
                 )
             )
-            .andReturn(responseHolder);
+            .andReturn(responseStream);
 
     EasyMock.replay(directOverlordClient);
 
@@ -129,7 +126,7 @@ public class RemoteTaskActionClientTest
                         new RequestBuilder(HttpMethod.POST, 
"/druid/indexer/v1/action")
                             .jsonContent(objectMapper, new 
TaskActionHolder(task, action))
                     ),
-                    EasyMock.anyObject(BytesFullResponseHandler.class)
+                    EasyMock.anyObject(InputStreamResponseHandler.class)
                 )
             )
             .andThrow(new ExecutionException(new 
HttpResponseException(responseHolder)));


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to