FrankChen021 commented on code in PR #20505:
URL: https://github.com/apache/druid/pull/20505#discussion_r4235825815


##########
indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/OverlordResource.java:
##########
@@ -506,34 +517,55 @@ public Response getWorkerConfigHistory(
   @Path("/action")
   @Produces(MediaType.APPLICATION_JSON)
   @ResourceFilters(StateResourceFilter.class)
-  public Response doAction(final TaskActionHolder holder)
+  public void doAction(
+      final TaskActionHolder holder,
+      @Context HttpServletRequest request
+  )
   {
-    return asLeaderWith(
-        taskMaster.getTaskActionClient(holder.getTask()),
-        new Function<>()
+    final AsyncContext asyncContext = request.startAsync();
+    final Optional<TaskActionClient> taskActionClient = 
taskMaster.getTaskActionClient(holder.getTask());
+    if (!taskActionClient.isPresent()) {
+      // Encourage client to try again soon, when we'll likely have a redirect 
set up
+      completeAsyncRequest(asyncContext, 
Status.SERVICE_UNAVAILABLE.getStatusCode(), null);
+      return;
+    }
+
+    final ListenableFuture<?> future = 
taskActionClient.get().submitAsync(holder.getAction());

Review Comment:
   [P1] Initial publish is outside the async timeout
   
   **Finding:** This invokes submitAsync before the async listener and 
15-minute timeout are installed. For the streaming publish actions handled by 
this PR, submitAsync calls performAsync synchronously and 
publishSegmentsWhenReady performs the first metadata/lock publish attempt 
inline before it returns a future. If that database or lock operation stalls, 
the servlet thread remains blocked and the request has no timeout or 
cancellation path, defeating the new async endpoint and allowing stalled 
publishes to consume Overlord request threads indefinitely.
   
   **Suggestion:** Dispatch the initial publish through an executor or 
otherwise obtain the future without running the first attempt on the servlet 
thread, and install the timeout/cancellation handling so it covers that first 
attempt as well.



##########
indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/OverlordResource.java:
##########
@@ -506,34 +517,55 @@ public Response getWorkerConfigHistory(
   @Path("/action")
   @Produces(MediaType.APPLICATION_JSON)
   @ResourceFilters(StateResourceFilter.class)
-  public Response doAction(final TaskActionHolder holder)
+  public void doAction(
+      final TaskActionHolder holder,
+      @Context HttpServletRequest request
+  )
   {
-    return asLeaderWith(
-        taskMaster.getTaskActionClient(holder.getTask()),
-        new Function<>()
+    final AsyncContext asyncContext = request.startAsync();
+    final Optional<TaskActionClient> taskActionClient = 
taskMaster.getTaskActionClient(holder.getTask());
+    if (!taskActionClient.isPresent()) {
+      // Encourage client to try again soon, when we'll likely have a redirect 
set up
+      completeAsyncRequest(asyncContext, 
Status.SERVICE_UNAVAILABLE.getStatusCode(), null);
+      return;
+    }
+
+    final ListenableFuture<?> future = 
taskActionClient.get().submitAsync(holder.getAction());
+    asyncContext.addListener(
+        ServletResourceUtils.createAsyncTimeoutListener(event -> {
+          future.cancel(true);

Review Comment:
   [P1] Timeout cancellation races the response callback
   
   **Finding:** Canceling this future can synchronously invoke the onFailure 
callback because the callback is registered with directExecutor below; that 
callback treats cancellation as an internal-server-error response and completes 
the AsyncContext before this handler tries to write the intended 504. A 
concurrent success or failure can race the same timeout path as well, so one 
request can produce a 500/200 instead of the promised gateway timeout and then 
attempt a second completion on a closed response.
   
   **Suggestion:** Serialize response completion with an atomic once guard, and 
make the timeout path claim the response or ignore the cancellation callback 
before canceling the underlying future.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to