markap14 commented on code in PR #11570:
URL: https://github.com/apache/nifi/pull/11570#discussion_r4220812632


##########
nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/RemovedConnectionDrainCoordinator.java:
##########
@@ -0,0 +1,611 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web;
+
+import org.apache.nifi.connectable.ConnectableType;
+import org.apache.nifi.controller.ScheduledState;
+import org.apache.nifi.web.api.dto.AffectedComponentDTO;
+import org.apache.nifi.web.api.entity.AffectedComponentEntity;
+import org.apache.nifi.web.util.CancellableTimedPause;
+import org.apache.nifi.web.util.ComponentLifecycle;
+import org.apache.nifi.web.util.InvalidComponentAction;
+import org.apache.nifi.web.util.LifecycleManagementException;
+import org.apache.nifi.web.util.Pause;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+import java.time.Duration;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.LongSupplier;
+import java.util.stream.Collectors;
+
+public final class RemovedConnectionDrainCoordinator {
+    private static final Logger logger = 
LoggerFactory.getLogger(RemovedConnectionDrainCoordinator.class);
+    static final Duration DEFAULT_DRAIN_TIMEOUT = Duration.ofSeconds(30);
+    private static final Duration DEFAULT_POLL_INTERVAL = 
Duration.ofMillis(250);
+
+    private final RemovedConnectionDrainClassifier classifier;
+    private final PauseFactory pauseFactory;
+    private final Duration drainTimeout;
+
+    public RemovedConnectionDrainCoordinator() {
+        this(new RemovedConnectionDrainClassifier(), new 
MonotonicPauseFactory(DEFAULT_POLL_INTERVAL, System::nanoTime), 
DEFAULT_DRAIN_TIMEOUT);
+    }
+
+    RemovedConnectionDrainCoordinator(final RemovedConnectionDrainClassifier 
classifier, final PauseFactory pauseFactory, final Duration drainTimeout) {
+        this.classifier = Objects.requireNonNull(classifier, "Removed 
Connection Drain Classifier required");
+        this.pauseFactory = Objects.requireNonNull(pauseFactory, "Pause 
Factory required");
+        this.drainTimeout = Objects.requireNonNull(drainTimeout, "Drain 
Timeout required");
+    }
+
+    public DrainResult coordinateDrain(final FlowUpdateImpact 
flowUpdateImpact, final RemovedConnectionDrainClassifier.Context context,
+                                       final ComponentLifecycle 
componentLifecycle, final URI requestUri, final String groupId,
+                                       final CancellationHandle 
cancellationHandle) throws LifecycleManagementException {
+        Objects.requireNonNull(flowUpdateImpact, "Flow Update Impact 
required");
+        Objects.requireNonNull(context, "Removed Connection Drain Context 
required");
+        Objects.requireNonNull(componentLifecycle, "Component Lifecycle 
required");
+        Objects.requireNonNull(requestUri, "Request URI required");
+        Objects.requireNonNull(groupId, "Group ID required");
+        Objects.requireNonNull(cancellationHandle, "Cancellation Handle 
required");
+
+        final DeadlinePause drainPause = 
pauseFactory.createDrainPause(drainTimeout);
+        final RemovedConnectionDrainClassifier.Context queueAwareContext = 
createQueueAwareContext(flowUpdateImpact, context, componentLifecycle, 
requestUri, drainPause);

Review Comment:
   [GPT-5.6 Sol] Cancellation can occur while this preflight is checking 
queues, but the cancellation callback is not installed until after preflight 
completes. When that happens, the callback handoff in `FlowUpdateResource` is 
still empty. Preflight can then return, this coordinator can proceed to 
`scheduleComponents(..., STOPPED, ...)`, and only afterward notice cancellation 
and restore the producers. On a healthy cluster the window is small, but 
sequential replicated checks across several removed connections can make it 
last seconds. Please check `cancellationHandle.isCancelled()` immediately 
before stopping producers so an already-cancelled update does not begin 
changing runtime state.



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

Reply via email to