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 9c871699c3 NIFI-12506 Added Threading for Status Analytics Retrieval
9c871699c3 is described below
commit 9c871699c3eb9d26e2a8e151442e6274b273bbef
Author: Timea Barna <[email protected]>
AuthorDate: Thu Dec 14 07:29:27 2023 +0100
NIFI-12506 Added Threading for Status Analytics Retrieval
This closes #8158
Signed-off-by: David Handermann <[email protected]>
---
.../apache/nifi/web/StandardNiFiServiceFacade.java | 34 ++-----
.../PredictionBasedParallelProcessingService.java | 35 +++++++
.../VirtualThreadParallelProcessingService.java | 112 +++++++++++++++++++++
.../src/main/resources/nifi-web-api-context.xml | 5 +
4 files changed, 163 insertions(+), 23 deletions(-)
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index 60f02abcb8..beaa059bef 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -100,7 +100,6 @@ import
org.apache.nifi.controller.service.ControllerServiceReference;
import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.controller.status.ProcessGroupStatus;
import org.apache.nifi.controller.status.ProcessorStatus;
-import org.apache.nifi.controller.status.analytics.StatusAnalytics;
import org.apache.nifi.controller.status.history.ProcessGroupStatusDescriptor;
import org.apache.nifi.diagnostics.DiagnosticLevel;
import org.apache.nifi.diagnostics.StorageUsage;
@@ -366,6 +365,7 @@ import org.apache.nifi.web.revision.RevisionUpdate;
import org.apache.nifi.web.revision.StandardRevisionClaim;
import org.apache.nifi.web.revision.StandardRevisionUpdate;
import org.apache.nifi.web.revision.UpdateRevisionTask;
+import org.apache.nifi.web.util.PredictionBasedParallelProcessingService;
import org.apache.nifi.web.util.SnippetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -457,6 +457,8 @@ public class StandardNiFiServiceFacade implements
NiFiServiceFacade {
private RuleViolationsManager ruleViolationsManager;
+ private PredictionBasedParallelProcessingService parallelProcessingService;
+
// -----------------------------------------
// Synchronization methods
// -----------------------------------------
@@ -6232,28 +6234,10 @@ public class StandardNiFiServiceFacade implements
NiFiServiceFacade {
PrometheusMetricsUtil.createAggregatedNifiMetrics(nifiMetricsRegistry,
aggregatedMetrics, instanceId,ROOT_PROCESS_GROUP, rootPGName, rootPGId);
// Get Connection Status Analytics (predictions, e.g.)
- Set<Connection> connections =
controllerFacade.getFlowManager().findAllConnections();
- for (Connection c : connections) {
- // If a ResourceNotFoundException is thrown, analytics hasn't been
enabled
- try {
- final StatusAnalytics statusAnalytics =
controllerFacade.getConnectionStatusAnalytics(c.getIdentifier());
-
PrometheusMetricsUtil.createConnectionStatusAnalyticsMetrics(connectionAnalyticsMetricsRegistry,
- statusAnalytics,
- instanceId,
- "Connection",
- c.getName(),
- c.getIdentifier(),
- c.getProcessGroup().getIdentifier(),
- c.getSource().getName(),
- c.getSource().getIdentifier(),
- c.getDestination().getName(),
- c.getDestination().getIdentifier()
- );
-
PrometheusMetricsUtil.aggregateConnectionPredictionMetrics(aggregatedMetrics,
statusAnalytics.getPredictions());
- } catch (ResourceNotFoundException rnfe) {
- break;
- }
- }
+ Collection<Map<String, Long>> predictions =
parallelProcessingService.createConnectionStatusAnalyticsMetricsAndCollectPredictions(
+ controllerFacade, connectionAnalyticsMetricsRegistry,
instanceId);
+
+ predictions.forEach((prediction) ->
PrometheusMetricsUtil.aggregateConnectionPredictionMetrics(aggregatedMetrics,
prediction));
PrometheusMetricsUtil.createAggregatedConnectionStatusAnalyticsMetrics(connectionAnalyticsMetricsRegistry,
aggregatedMetrics, instanceId, ROOT_PROCESS_GROUP, rootPGName, rootPGId);
// Create a query to get all bulletins
@@ -6764,4 +6748,8 @@ public class StandardNiFiServiceFacade implements
NiFiServiceFacade {
public void setRuleViolationsManager(RuleViolationsManager
ruleViolationsManager) {
this.ruleViolationsManager = ruleViolationsManager;
}
+
+ public void
setParallelProcessingService(PredictionBasedParallelProcessingService
parallelProcessingService) {
+ this.parallelProcessingService = parallelProcessingService;
+ }
}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/PredictionBasedParallelProcessingService.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/PredictionBasedParallelProcessingService.java
new file mode 100644
index 0000000000..397ae8d881
--- /dev/null
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/PredictionBasedParallelProcessingService.java
@@ -0,0 +1,35 @@
+/*
+ * 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.util;
+
+import org.apache.nifi.prometheus.util.ConnectionAnalyticsMetricsRegistry;
+import org.apache.nifi.web.controller.ControllerFacade;
+
+import java.util.Collection;
+import java.util.Map;
+
+public interface PredictionBasedParallelProcessingService {
+ /**
+ * @return a connection prediction collection
+ *
+ * @param controllerFacade controller facade
+ * @param connectionAnalyticsMetricsRegistry connection analytics metrics
registry
+ * @param instanceId instance id of the flow controller
+ */
+ Collection<Map<String, Long>>
createConnectionStatusAnalyticsMetricsAndCollectPredictions(
+ ControllerFacade controllerFacade,
ConnectionAnalyticsMetricsRegistry connectionAnalyticsMetricsRegistry, String
instanceId);
+}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/VirtualThreadParallelProcessingService.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/VirtualThreadParallelProcessingService.java
new file mode 100644
index 0000000000..a20fa08a6b
--- /dev/null
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/VirtualThreadParallelProcessingService.java
@@ -0,0 +1,112 @@
+/*
+ * 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.util;
+
+import jakarta.ws.rs.WebApplicationException;
+import org.apache.nifi.connectable.Connection;
+import org.apache.nifi.controller.status.analytics.StatusAnalytics;
+import org.apache.nifi.prometheus.util.ConnectionAnalyticsMetricsRegistry;
+import org.apache.nifi.prometheus.util.PrometheusMetricsUtil;
+import org.apache.nifi.util.FormatUtils;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.controller.ControllerFacade;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class VirtualThreadParallelProcessingService implements
PredictionBasedParallelProcessingService, Closeable {
+ private boolean analyticsEnabled;
+ private ExecutorService parallelProcessingExecutorService;
+ private long parallelProcessingTimeout;
+
+ public VirtualThreadParallelProcessingService(final NiFiProperties
properties) {
+ // We need to make processing timeout shorter than the web request
timeout as if they overlap Jetty may throw IllegalStateException
+ parallelProcessingTimeout =
Math.round(FormatUtils.getPreciseTimeDuration(
+ properties.getProperty(NiFiProperties.WEB_REQUEST_TIMEOUT, "1
min"), TimeUnit.MILLISECONDS)) - 5000;
+
+ analyticsEnabled = Boolean.parseBoolean(
+
properties.getProperty(NiFiProperties.ANALYTICS_PREDICTION_ENABLED,
Boolean.FALSE.toString()));
+
+ if (analyticsEnabled) {
+ this.parallelProcessingExecutorService =
Executors.newVirtualThreadPerTaskExecutor();
+ }
+ }
+
+ @Override
+ public Collection<Map<String, Long>>
createConnectionStatusAnalyticsMetricsAndCollectPredictions(
+ ControllerFacade controllerFacade,
ConnectionAnalyticsMetricsRegistry connectionAnalyticsMetricsRegistry, String
instanceId) {
+
+ Collection<Map<String, Long>> predictions =
Collections.synchronizedList(new ArrayList<>());
+
+ if (!analyticsEnabled) {
+ return predictions;
+ }
+
+ final Set<Connection> connections =
controllerFacade.getFlowManager().findAllConnections();
+ final CountDownLatch countDownLatch = new
CountDownLatch(connections.size());
+ try {
+ for (Connection c : connections) {
+ parallelProcessingExecutorService.execute(() -> {
+ try {
+ final StatusAnalytics statusAnalytics =
controllerFacade.getConnectionStatusAnalytics(c.getIdentifier());
+
PrometheusMetricsUtil.createConnectionStatusAnalyticsMetrics(connectionAnalyticsMetricsRegistry,
+ statusAnalytics,
+ instanceId,
+ "Connection",
+ c.getName(),
+ c.getIdentifier(),
+ c.getProcessGroup().getIdentifier(),
+ c.getSource().getName(),
+ c.getSource().getIdentifier(),
+ c.getDestination().getName(),
+ c.getDestination().getIdentifier()
+ );
+ predictions.add(statusAnalytics.getPredictions());
+ } finally {
+ countDownLatch.countDown();
+ }
+ });
+ }
+ } finally {
+ try {
+ boolean finished =
countDownLatch.await(parallelProcessingTimeout, TimeUnit.MILLISECONDS);
+ if (!finished) {
+ throw new WebApplicationException("Populating flow metrics
timed out");
+ }
+ } catch (InterruptedException e) {
+ throw new WebApplicationException("Populating flow metrics
cancelled");
+ }
+ }
+ return predictions;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (parallelProcessingExecutorService != null) {
+ parallelProcessingExecutorService.close();
+ }
+ }
+}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
index 8f65571e42..833ff7e65a 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
@@ -363,6 +363,7 @@
<property name="flowRegistryDAO" ref="flowRegistryDAO" />
<property name="parameterContextDAO" ref="parameterContextDAO" />
<property name="ruleViolationsManager" ref="ruleViolationsManager" />
+ <property name="parallelProcessingService"
ref="parallelProcessingService" />
</bean>
<!-- component ui extension configuration context -->
@@ -776,4 +777,8 @@
<!-- NiFi locking -->
<bean id="serviceFacadeLock"
class="org.apache.nifi.web.NiFiServiceFacadeLock"/>
+
+ <bean id="parallelProcessingService"
class="org.apache.nifi.web.util.VirtualThreadParallelProcessingService">
+ <constructor-arg ref="nifiProperties" />
+ </bean>
</beans>