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


##########
multi-stage-query/src/main/java/org/apache/druid/msq/dart/worker/DartWorkerClientImpl.java:
##########
@@ -140,8 +147,26 @@ public void close()
   }
 
   @Override
-  public ListenableFuture<?> stopWorker(String workerId)
+  public ListenableFuture<Void> postWorkOrder(final String workerId, final 
WorkOrder workOrder)
+  {
+    final ListenableFuture<Void> future = super.postWorkOrder(workerId, 
workOrder);

Review Comment:
   Confirmed fixed in `9b7eafa`: the stop-state check, `/workOrder` dispatch, 
and active-work-order registration are now serialized under `clientMap`, so the 
original late-`/workOrder` race is resolved. I rechecked all 5 changed files 
and found no remaining issue with that specific finding.
   
   <!-- mergelens:review -->



##########
multi-stage-query/src/main/java/org/apache/druid/msq/dart/worker/DartWorkerClientImpl.java:
##########
@@ -184,6 +223,39 @@ private Pair<ServiceClient, Closeable> 
getClientAndLocator(final String workerId
     }
   }
 
+  private static class RequestTrackingClient implements ServiceClient
+  {
+    private final ServiceClient delegate;
+    private final Set<ListenableFuture<?>> activeRequests;
+
+    private RequestTrackingClient(
+        final ServiceClient delegate,
+        final Set<ListenableFuture<?>> activeRequests
+    )
+    {
+      this.delegate = delegate;
+      this.activeRequests = activeRequests;
+    }
+
+    @Override
+    public <IntermediateType, FinalType> ListenableFuture<FinalType> 
asyncRequest(
+        final RequestBuilder requestBuilder,
+        final HttpResponseHandler<IntermediateType, FinalType> handler
+    )
+    {
+      final ListenableFuture<FinalType> future = 
delegate.asyncRequest(requestBuilder, handler);
+      activeRequests.add(future);

Review Comment:
   [P2] Register requests atomically with close
   
   `RequestTrackingClient.asyncRequest` invokes `delegate.asyncRequest` before 
adding its future to `activeRequests`. For `postFinish`, fetches, or 
`stopWorker`, another thread can enter `close()` after the delegate has started 
the request but before this add; `close()` then snapshots and clears the set 
and closes the locators, while the future is added afterward and is never 
canceled. An in-flight request can therefore survive query teardown (and this 
is another way for a stop request to be lost). Register the future under the 
same lifecycle lock or use a tracker that checks a closed flag after 
registration, and test this race.



##########
multi-stage-query/src/main/java/org/apache/druid/msq/dart/worker/DartWorkerClientImpl.java:
##########
@@ -127,6 +138,13 @@ public void closeClient(final String workerIdString)
   public void close()
   {
     synchronized (clientMap) {
+      closed = true;
+
+      // Cancel requests before closing locators so in-flight requests do not 
continue retrying.
+      final List<ListenableFuture<?>> requests = new 
ArrayList<>(activeRequests);
+      activeRequests.clear();
+      requests.forEach(request -> request.cancel(true));

Review Comment:
   [P1] Do not cancel stop commands during close
   
   `close()` now cancels every tracked future, including the `/stop` future 
created by `stopWorker`. This can race with controller cancellation: 
`ControllerHolder.cancel()` calls `ControllerImpl.stop()` on one thread, which 
sets `DartWorkerManager` to STOPPED and waits for its stop future, while the 
controller loop processes the queued cancellation, sees STOPPED, and exits 
through `Closer`, invoking this `close()` before the first `stop(true)` 
returns. The canceled future makes `successfulAsList` finish without an 
acknowledgement (and a still-scheduled request may never be sent), defeating 
the manager's unlimited retry; its comment explicitly says a lost stop leaves a 
worker zombie until server restart. Coordinate close with the stop wait or 
exempt/drain `/stop` requests, and add a regression test for this concurrent 
path.



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