This is an automated email from the ASF dual-hosted git repository.

pvillard 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 a316f1648f NIFI-15404 Scheduled Security Maintenance Tasks with 
Virtual Threads
a316f1648f is described below

commit a316f1648f46c5b0132a95a57b546d3062b23762
Author: exceptionfactory <[email protected]>
AuthorDate: Mon Dec 29 17:34:32 2025 -0600

    NIFI-15404 Scheduled Security Maintenance Tasks with Virtual Threads
    
    - Added Task Scheduler Configuration with Virtual Threads configured
    - Replaced separate Thread Pools with shared Task Scheduler
    
    Signed-off-by: Pierre Villard <[email protected]>
    
    This closes #10708.
---
 .../configuration/SslContextConfiguration.java     | 25 +++++--------
 .../configuration/TaskSchedulerConfiguration.java  | 43 ++++++++++++++++++++++
 .../JwtAuthenticationSecurityConfiguration.java    | 24 ++++--------
 .../configuration/OidcSecurityConfiguration.java   | 20 +++-------
 4 files changed, 66 insertions(+), 46 deletions(-)

diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/SslContextConfiguration.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/SslContextConfiguration.java
index 85a14f5462..8323b53bc3 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/SslContextConfiguration.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/SslContextConfiguration.java
@@ -31,7 +31,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.scheduling.TaskScheduler;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.X509ExtendedKeyManager;
@@ -79,11 +79,18 @@ public class SslContextConfiguration {
 
     private NiFiProperties properties;
 
+    private TaskScheduler taskScheduler;
+
     @Autowired
     public void setProperties(final NiFiProperties properties) {
         this.properties = properties;
     }
 
+    @Autowired
+    public void setTaskScheduler(final TaskScheduler taskScheduler) {
+        this.taskScheduler = taskScheduler;
+    }
+
     @Bean
     public SSLContext sslContext() {
         return FrameworkSslContextHolder.getSslContext();
@@ -123,7 +130,7 @@ public class SslContextConfiguration {
                 final WatchService watchService = storeWatchService();
                 command = new WatchServiceMonitorCommand(watchService, 
changedPathListener);
 
-                watchServiceScheduler().scheduleAtFixedRate(command, 
reloadDuration);
+                taskScheduler.scheduleAtFixedRate(command, reloadDuration);
                 logger.info("Scheduled Security Store Monitor with Duration 
[{}]", reloadDuration);
             } else {
                 throw new IllegalStateException("Key Manager Listener or Trust 
Manager Listener not found");
@@ -134,20 +141,6 @@ public class SslContextConfiguration {
         return command;
     }
 
-    @Bean
-    public ThreadPoolTaskScheduler watchServiceScheduler() {
-        final ThreadPoolTaskScheduler scheduler;
-
-        if (isReloadEnabled()) {
-            scheduler = new ThreadPoolTaskScheduler();
-            scheduler.setThreadNamePrefix("Security Store Monitor ");
-        } else {
-            scheduler = null;
-        }
-
-        return scheduler;
-    }
-
     @Bean
     public WatchService storeWatchService() {
         final WatchService watchService;
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/TaskSchedulerConfiguration.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/TaskSchedulerConfiguration.java
new file mode 100644
index 0000000000..31487387e3
--- /dev/null
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/TaskSchedulerConfiguration.java
@@ -0,0 +1,43 @@
+/*
+ * 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.framework.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+
+/**
+ * Task Scheduler Configuration class for Spring Application
+ */
+@Configuration
+public class TaskSchedulerConfiguration {
+    private static final String APPLICATION_THREAD_NAME_PREFIX = 
"ApplicationThread-";
+
+    /**
+     * Application Task Scheduler configured with Virtual Threads for 
infrequent operations
+     *
+     * @return Task Scheduler
+     */
+    @Bean
+    public TaskScheduler taskScheduler() {
+        final ThreadPoolTaskScheduler taskScheduler = new 
ThreadPoolTaskScheduler();
+        taskScheduler.setThreadNamePrefix(APPLICATION_THREAD_NAME_PREFIX);
+        taskScheduler.setVirtualThreads(true);
+        return taskScheduler;
+    }
+}
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/configuration/JwtAuthenticationSecurityConfiguration.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/configuration/JwtAuthenticationSecurityConfiguration.java
index 8a6c26f998..c9390633b2 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/configuration/JwtAuthenticationSecurityConfiguration.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/configuration/JwtAuthenticationSecurityConfiguration.java
@@ -39,7 +39,7 @@ import 
org.apache.nifi.web.security.jwt.revocation.command.RevocationExpirationC
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.scheduling.TaskScheduler;
 import org.springframework.security.authentication.AuthenticationDetailsSource;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.oauth2.jwt.JwtDecoder;
@@ -59,6 +59,8 @@ public class JwtAuthenticationSecurityConfiguration {
 
     private final NiFiProperties niFiProperties;
 
+    private final TaskScheduler taskScheduler;
+
     private final Authorizer authorizer;
 
     private final JwtDecoder jwtDecoder;
@@ -74,6 +76,7 @@ public class JwtAuthenticationSecurityConfiguration {
     @Autowired
     public JwtAuthenticationSecurityConfiguration(
             final NiFiProperties niFiProperties,
+            final TaskScheduler taskScheduler,
             final Authorizer authorizer,
             final JwtDecoder jwtDecoder,
             final JwtRevocationService jwtRevocationService,
@@ -81,6 +84,7 @@ public class JwtAuthenticationSecurityConfiguration {
             final VerificationKeyService verificationKeyService
     ) {
         this.niFiProperties = niFiProperties;
+        this.taskScheduler = taskScheduler;
         this.authorizer = authorizer;
         this.jwtDecoder = jwtDecoder;
         this.jwtRevocationService = jwtRevocationService;
@@ -192,7 +196,7 @@ public class JwtAuthenticationSecurityConfiguration {
     @Bean
     public KeyGenerationCommand keyGenerationCommand(final KeyPairGenerator 
keyPairGenerator) {
         final KeyGenerationCommand command = new 
KeyGenerationCommand(jwsSignerProvider(), verificationKeySelector, 
keyPairGenerator);
-        commandScheduler().scheduleAtFixedRate(command, keyRotationPeriod);
+        taskScheduler.scheduleAtFixedRate(command, keyRotationPeriod);
         return command;
     }
 
@@ -204,7 +208,7 @@ public class JwtAuthenticationSecurityConfiguration {
     @Bean
     public KeyExpirationCommand keyExpirationCommand() {
         final KeyExpirationCommand command = new 
KeyExpirationCommand(verificationKeyService);
-        commandScheduler().scheduleAtFixedRate(command, keyRotationPeriod);
+        taskScheduler.scheduleAtFixedRate(command, keyRotationPeriod);
         return command;
     }
 
@@ -216,19 +220,7 @@ public class JwtAuthenticationSecurityConfiguration {
     @Bean
     public RevocationExpirationCommand revocationExpirationCommand() {
         final RevocationExpirationCommand command = new 
RevocationExpirationCommand(jwtRevocationService);
-        commandScheduler().scheduleAtFixedRate(command, keyRotationPeriod);
+        taskScheduler.scheduleAtFixedRate(command, keyRotationPeriod);
         return command;
     }
-
-    /**
-     * Command Scheduler responsible for running commands in background thread
-     *
-     * @return Thread Pool Task Scheduler with named threads
-     */
-    @Bean
-    public ThreadPoolTaskScheduler commandScheduler() {
-        final ThreadPoolTaskScheduler scheduler = new 
ThreadPoolTaskScheduler();
-        
scheduler.setThreadNamePrefix(JwtAuthenticationSecurityConfiguration.class.getSimpleName());
-        return scheduler;
-    }
 }
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/configuration/OidcSecurityConfiguration.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/configuration/OidcSecurityConfiguration.java
index 901519e67c..211975650e 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/configuration/OidcSecurityConfiguration.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/configuration/OidcSecurityConfiguration.java
@@ -47,7 +47,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.cache.caffeine.CaffeineCache;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.scheduling.TaskScheduler;
 import org.springframework.security.authentication.AuthenticationManager;
 import 
org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
 import 
org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
@@ -95,6 +95,8 @@ public class OidcSecurityConfiguration {
 
     private final NiFiProperties properties;
 
+    private final TaskScheduler taskScheduler;
+
     private final StateManagerProvider stateManagerProvider;
 
     private final PropertyEncryptor propertyEncryptor;
@@ -118,6 +120,7 @@ public class OidcSecurityConfiguration {
     @Autowired
     public OidcSecurityConfiguration(
             final NiFiProperties properties,
+            final TaskScheduler taskScheduler,
             final StateManagerProvider stateManagerProvider,
             final PropertyEncryptor propertyEncryptor,
             final BearerTokenProvider bearerTokenProvider,
@@ -132,6 +135,7 @@ public class OidcSecurityConfiguration {
             final LogoutRequestManager logoutRequestManager
     ) {
         this.properties = Objects.requireNonNull(properties, "Properties 
required");
+        this.taskScheduler = Objects.requireNonNull(taskScheduler, "Task 
Scheduler required");
         this.stateManagerProvider = 
Objects.requireNonNull(stateManagerProvider, "State Manager Provider required");
         this.propertyEncryptor = Objects.requireNonNull(propertyEncryptor, 
"Property Encryptor required");
         this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, 
"Bearer Token Provider required");
@@ -313,22 +317,10 @@ public class OidcSecurityConfiguration {
     @Bean
     public AuthorizedClientExpirationCommand 
authorizedClientExpirationCommand() {
         final AuthorizedClientExpirationCommand command = new 
AuthorizedClientExpirationCommand(authorizedClientRepository(), 
tokenRevocationResponseClient());
-        oidcCommandScheduler().scheduleAtFixedRate(command, keyRotationPeriod);
+        taskScheduler.scheduleAtFixedRate(command, keyRotationPeriod);
         return command;
     }
 
-    /**
-     * Command Scheduled for OpenID Connect operations
-     *
-     * @return Thread Pool Task Executor
-     */
-    @Bean
-    public ThreadPoolTaskScheduler oidcCommandScheduler() {
-        final ThreadPoolTaskScheduler scheduler = new 
ThreadPoolTaskScheduler();
-        
scheduler.setThreadNamePrefix(OidcSecurityConfiguration.class.getSimpleName());
-        return scheduler;
-    }
-
     /**
      * Authorized Client Converter for OpenID Connect Tokens supporting 
serialization of OpenID Connect Tokens
      *

Reply via email to