mirror of https://github.com/apache/nifi.git
NIFI-6807: When a Controller Service's state is transitioned to ENABLING, complete the Future successfully, even if the Controller Service is not valid. The Controller Service will remain in the ENABLING state until it is made valid, at which point it will ENABLE (unless explicitly disabled first). This allows us to Enable a Controller Service and its referencing components, even if the referencing component is still invalid due to it not yet recognizing the the referenced service has been enabled.
This closes #3841
This commit is contained in:
parent
81fc2768c9
commit
3f270f184c
|
@ -66,7 +66,7 @@ public class ServiceStateTransition {
|
||||||
|
|
||||||
validateReferences(serviceNode);
|
validateReferences(serviceNode);
|
||||||
|
|
||||||
enabledFutures.stream().forEach(future -> future.complete(null));
|
enabledFutures.forEach(future -> future.complete(null));
|
||||||
return true;
|
return true;
|
||||||
} finally {
|
} finally {
|
||||||
writeLock.unlock();
|
writeLock.unlock();
|
||||||
|
|
|
@ -413,8 +413,9 @@ public class StandardControllerServiceNode extends AbstractComponentNode impleme
|
||||||
final ConfigurationContext configContext = new StandardConfigurationContext(StandardControllerServiceNode.this, controllerServiceProvider, null, getVariableRegistry());
|
final ConfigurationContext configContext = new StandardConfigurationContext(StandardControllerServiceNode.this, controllerServiceProvider, null, getVariableRegistry());
|
||||||
|
|
||||||
if (!isActive()) {
|
if (!isActive()) {
|
||||||
LOG.debug("{} is no longer active so will not attempt to enable it", StandardControllerServiceNode.this);
|
LOG.warn("{} is no longer active so will no longer attempt to enable it", StandardControllerServiceNode.this);
|
||||||
stateTransition.disable();
|
stateTransition.disable();
|
||||||
|
future.complete(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,15 +434,16 @@ public class StandardControllerServiceNode extends AbstractComponentNode impleme
|
||||||
|
|
||||||
boolean shouldEnable;
|
boolean shouldEnable;
|
||||||
synchronized (active) {
|
synchronized (active) {
|
||||||
shouldEnable = active.get() && stateTransition.enable();
|
shouldEnable = active.get() && stateTransition.enable(); // Transitioning the state to ENABLED will complete our future.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldEnable) {
|
if (!shouldEnable) {
|
||||||
LOG.debug("Disabling service {} after it has been enabled due to disable action being initiated.", service);
|
LOG.info("Disabling service {} after it has been enabled due to disable action being initiated.", service);
|
||||||
// Can only happen if user initiated DISABLE operation before service finished enabling. It's state will be
|
// Can only happen if user initiated DISABLE operation before service finished enabling. It's state will be
|
||||||
// set to DISABLING (see disable() operation)
|
// set to DISABLING (see disable() operation)
|
||||||
invokeDisable(configContext);
|
invokeDisable(configContext);
|
||||||
stateTransition.disable();
|
stateTransition.disable();
|
||||||
|
future.complete(null);
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Successfully enabled {}", service);
|
LOG.info("Successfully enabled {}", service);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,6 @@ import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
@ -571,16 +570,7 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
||||||
for (final ControllerServiceNode nodeToEnable : recursiveReferences) {
|
for (final ControllerServiceNode nodeToEnable : recursiveReferences) {
|
||||||
if (!nodeToEnable.isActive()) {
|
if (!nodeToEnable.isActive()) {
|
||||||
logger.debug("Enabling {} because it references {}", nodeToEnable, serviceNode);
|
logger.debug("Enabling {} because it references {}", nodeToEnable, serviceNode);
|
||||||
final Future<?> enableFuture = enableControllerService(nodeToEnable);
|
enableControllerService(nodeToEnable);
|
||||||
try {
|
|
||||||
enableFuture.get();
|
|
||||||
} catch (final ExecutionException ee) {
|
|
||||||
throw new IllegalStateException("Failed to enable Controller Service " + nodeToEnable, ee.getCause());
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
throw new IllegalStateException("Interrupted while enabling Controller Service");
|
|
||||||
}
|
|
||||||
|
|
||||||
updated.add(nodeToEnable);
|
updated.add(nodeToEnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue