This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 7edf0d4e2a NIFI-12693: Moved notification of python process that a
Processor was removed to a background (virtual) thread. Also noted in testing
that in one instance a Python Processor never became valid because it had
cached property descriptors before the processor was fully initialized, so
updated code to ensure that we do not cache values before initialization is
completed.
7edf0d4e2a is described below
commit 7edf0d4e2aee21949bc3ef755ca4b27fa324d20f
Author: Mark Payne <[email protected]>
AuthorDate: Tue Jan 30 10:58:22 2024 -0500
NIFI-12693: Moved notification of python process that a Processor was
removed to a background (virtual) thread. Also noted in testing that in one
instance a Python Processor never became
valid because it had cached property descriptors before the processor was
fully initialized, so updated code to ensure that we do not cache values before
initialization is completed.
This closes #8315
Signed-off-by: David Handermann <[email protected]>
---
.../apache/nifi/groups/StandardProcessGroup.java | 21 ++++++------
.../nifi/web/dao/impl/StandardProcessorDAO.java | 2 +-
.../org/apache/nifi/py4j/StandardPythonBridge.java | 37 ++++++++++++++--------
.../python/processor/PythonProcessorProxy.java | 8 ++---
4 files changed, 38 insertions(+), 30 deletions(-)
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
index 78579458e3..e9db230087 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
@@ -1263,6 +1263,14 @@ public final class StandardProcessGroup implements
ProcessGroup {
}
}
+ // Remove connections prior to removing the Processor. If there is
any failure in removing the Processor or the associated cleanup,
+ // we can handle that. However, we could have many potential
issues if Connections exist whose source or destination does not exist.
+ // must copy to avoid a concurrent modification
+ final List<Connection> copy = new
ArrayList<>(processor.getConnections());
+ for (final Connection conn : copy) {
+ removeConnection(conn);
+ }
+
processors.remove(id);
onComponentModified();
@@ -1274,18 +1282,7 @@ public final class StandardProcessGroup implements
ProcessGroup {
logRepository.removeAllObservers();
}
- scheduler.submitFrameworkTask(new Runnable() {
- @Override
- public void run() {
-
stateManagerProvider.onComponentRemoved(processor.getIdentifier());
- }
- });
-
- // must copy to avoid a concurrent modification
- final Set<Connection> copy = new
HashSet<>(processor.getConnections());
- for (final Connection conn : copy) {
- removeConnection(conn);
- }
+ scheduler.submitFrameworkTask(() ->
stateManagerProvider.onComponentRemoved(processor.getIdentifier()));
removed = true;
LOG.info("{} removed from flow", processor);
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessorDAO.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessorDAO.java
index c4198fe282..552b82fdeb 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessorDAO.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessorDAO.java
@@ -589,7 +589,7 @@ public class StandardProcessorDAO extends ComponentDAO
implements ProcessorDAO {
try {
// attempt remove the processor
processor.getProcessGroup().removeProcessor(processor);
- } catch (ComponentLifeCycleException plce) {
+ } catch (final ComponentLifeCycleException plce) {
throw new NiFiCoreException(plce.getMessage(), plce);
}
}
diff --git
a/nifi-nar-bundles/nifi-py4j-bundle/nifi-py4j-bridge/src/main/java/org/apache/nifi/py4j/StandardPythonBridge.java
b/nifi-nar-bundles/nifi-py4j-bundle/nifi-py4j-bridge/src/main/java/org/apache/nifi/py4j/StandardPythonBridge.java
index eb568dfdad..e3f735bb01 100644
---
a/nifi-nar-bundles/nifi-py4j-bundle/nifi-py4j-bridge/src/main/java/org/apache/nifi/py4j/StandardPythonBridge.java
+++
b/nifi-nar-bundles/nifi-py4j-bundle/nifi-py4j-bridge/src/main/java/org/apache/nifi/py4j/StandardPythonBridge.java
@@ -38,11 +38,11 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -162,18 +162,29 @@ public class StandardPythonBridge implements PythonBridge
{
return;
}
- // Find the Python Process that has the Processor, if any, and
remove it.
- // If there are no additional Processors in the Python Process,
remove it from our list and shut down the process.
- final Iterator<PythonProcess> processItr = processes.iterator();
// Use iterator so we can call remove()
- while (processItr.hasNext()) {
- final PythonProcess process = processItr.next();
- final boolean removed = process.removeProcessor(identifier);
- if (removed && process.getProcessorCount() == 0) {
- processItr.remove();
- process.shutdown();
- break;
+ Thread.ofVirtual().name("Remove Python Processor " +
identifier).start(() -> {
+ PythonProcess toRemove = null;
+
+ try {
+ // Find the Python Process that has the Processor, if any,
and remove it.
+ // If there are no additional Processors in the Python
Process, remove it from our list and shut down the process.
+ // Use iterator so we can call remove()
+ for (final PythonProcess process : processes) {
+ final boolean removed =
process.removeProcessor(identifier);
+ if (removed && process.getProcessorCount() == 0) {
+ toRemove = process;
+ break;
+ }
+ }
+
+ if (toRemove != null) {
+ processes.remove(toRemove);
+ toRemove.shutdown();
+ }
+ } catch (final Exception e) {
+ logger.error("Failed to trigger removal of Python
Processor with ID {}", identifier, e);
}
- }
+ });
processorCountByType.merge(extensionId, -1, Integer::sum);
} else {
@@ -198,7 +209,7 @@ public class StandardPythonBridge implements PythonBridge {
// isolation (which is the case when Extension Manager creates a temp
component), or if an existing process
// consists only of processors that don't prefer isolation. I.e., we
don't want to collocate two Processors if
// they both prefer isolation.
- final List<PythonProcess> processesForType =
processesByProcessorType.computeIfAbsent(extensionId, key -> new ArrayList<>());
+ final List<PythonProcess> processesForType =
processesByProcessorType.computeIfAbsent(extensionId, key -> new
CopyOnWriteArrayList<>());
for (final PythonProcess pythonProcess : processesForType) {
if (!preferIsolatedProcess ||
!pythonProcess.containsIsolatedProcessor()) {
logger.debug("Using {} to create Processor of type {}",
pythonProcess, extensionId.type());
diff --git
a/nifi-nar-bundles/nifi-py4j-bundle/nifi-py4j-bridge/src/main/java/org/apache/nifi/python/processor/PythonProcessorProxy.java
b/nifi-nar-bundles/nifi-py4j-bundle/nifi-py4j-bridge/src/main/java/org/apache/nifi/python/processor/PythonProcessorProxy.java
index 9ee4fcb212..a20ad583c2 100644
---
a/nifi-nar-bundles/nifi-py4j-bundle/nifi-py4j-bridge/src/main/java/org/apache/nifi/python/processor/PythonProcessorProxy.java
+++
b/nifi-nar-bundles/nifi-py4j-bundle/nifi-py4j-bridge/src/main/java/org/apache/nifi/python/processor/PythonProcessorProxy.java
@@ -126,7 +126,7 @@ public abstract class PythonProcessorProxy extends
AbstractProcessor implements
return this.cachedPropertyDescriptors;
}
- if (bridge == null) {
+ if (getState() != LoadState.FINISHED_LOADING) {
return Collections.emptyList();
}
@@ -202,7 +202,7 @@ public abstract class PythonProcessorProxy extends
AbstractProcessor implements
return cachedDynamicDescriptors.get(propertyDescriptorName);
}
- if (bridge == null) {
+ if (getState() != LoadState.FINISHED_LOADING) {
return null;
}
@@ -221,7 +221,7 @@ public abstract class PythonProcessorProxy extends
AbstractProcessor implements
return supportsDynamicProperties;
}
- if (bridge == null) {
+ if (getState() != LoadState.FINISHED_LOADING) {
return false;
}
@@ -266,7 +266,7 @@ public abstract class PythonProcessorProxy extends
AbstractProcessor implements
}
private Set<Relationship> fetchRelationshipsFromPythonProcessor() {
- if (bridge == null) {
+ if (getState() != LoadState.FINISHED_LOADING) {
return Collections.emptySet();
}