From bca80060af9eacf281766481dde2568f30ab90b4 Mon Sep 17 00:00:00 2001 From: Yavor16 Date: Fri, 6 Nov 2026 13:03:04 +0200 Subject: [PATCH] Fix cloud logging service dedicated executor --- .../multiapps/controller/core/Messages.java | 3 ++ .../CloudLoggingServiceClient.java | 2 +- .../core/util/ApplicationConfiguration.java | 54 +++++++++++++++++++ .../AsyncProcessLoggerConfiguration.java | 15 ++++++ 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Messages.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Messages.java index 7bb6bbdacd..ac7aa8401e 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Messages.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/Messages.java @@ -193,6 +193,9 @@ public final class Messages { public static final String SPRING_SCHEDULER_TASK_EXECUTOR_THREADS = "Spring scheduler task executor threads: {0}"; public static final String FILES_ASYNC_UPLOAD_EXECUTOR_MAX_THREADS = "Files async executor max threads: {0}"; public static final String DEPLOY_FROM_URL_EXECUTOR_MAX_THREADS = "Deploy from URL executor max threads: {0}"; + public static final String CLOUD_LOGGING_EXECUTOR_CORE_THREADS = "Cloud logging executor core threads: {0}"; + public static final String CLOUD_LOGGING_EXECUTOR_MAX_THREADS = "Cloud logging executor max threads: {0}"; + public static final String CLOUD_LOGGING_EXECUTOR_QUEUE_CAPACITY = "Cloud logging executor queue capacity: {0}"; public static final String DEPLOY_FROM_URL_ADDRESS_DENY_LIST_0 = "Deploy from URL address deny list: {0}"; public static final String DEPLOY_FROM_URL_ADDRESS_VALIDATION_ENABLED_0 = "Deploy from URL address validation enabled: {0}"; public static final String DEPLOY_FROM_URL_TARGET_ADDRESS_0_DENIED_FOR_JOB_WITH_ID_1 = "Download target host \"{0}\" resolves to a denied address. Job id: {1}"; diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cloudlogging/CloudLoggingServiceClient.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cloudlogging/CloudLoggingServiceClient.java index 77ba3314a4..8c4f4cde26 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cloudlogging/CloudLoggingServiceClient.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cloudlogging/CloudLoggingServiceClient.java @@ -62,7 +62,7 @@ public void removeClientFromCache(String operationId) { webClientCache.remove(operationId); } - @Async("asyncExecutor") + @Async("cloudLoggingAsyncExecutor") public void sendLogsToCloudLoggingService(LoggingConfiguration loggingConfiguration, List logEntryBatch) { WebClient webClient; diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/ApplicationConfiguration.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/ApplicationConfiguration.java index 020d17782b..0ede418264 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/ApplicationConfiguration.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/ApplicationConfiguration.java @@ -96,6 +96,9 @@ public class ApplicationConfiguration { static final String CFG_SPRING_SCHEDULER_TASK_EXECUTOR_THREADS = "SPRING_SCHEDULER_TASK_EXECUTOR_THREADS"; static final String CFG_FILES_ASYNC_UPLOAD_EXECUTOR_MAX_THREADS = "FILES_ASYNC_UPLOAD_EXECUTOR_THREADS"; static final String CFG_DEPLOY_FROM_URL_EXECUTOR_MAX_THREADS = "DEPLOY_FROM_URL_EXECUTOR_MAX_THREADS"; + static final String CFG_CLOUD_LOGGING_EXECUTOR_CORE_THREADS = "CLOUD_LOGGING_EXECUTOR_CORE_THREADS"; + static final String CFG_CLOUD_LOGGING_EXECUTOR_MAX_THREADS = "CLOUD_LOGGING_EXECUTOR_MAX_THREADS"; + static final String CFG_CLOUD_LOGGING_EXECUTOR_QUEUE_CAPACITY = "CLOUD_LOGGING_EXECUTOR_QUEUE_CAPACITY"; static final String CFG_ENABLE_ON_START_FILES_WITHOUT_CONTENT_CLEANER = "ENABLE_ON_START_FILES_WITHOUT_CONTENT_CLEANER"; static final String CFG_THREADS_FOR_FILE_UPLOAD_TO_CONTROLLER = "THREADS_FOR_FILE_UPLOAD_TO_CONTROLLER"; static final String CFG_THREADS_FOR_FILE_STORAGE_UPLOAD = "THREADS_FOR_FILE_STORAGE_UPLOAD"; @@ -163,6 +166,9 @@ public class ApplicationConfiguration { public static final int DEFAULT_SPRING_SCHEDULER_TASK_EXECUTOR_THREADS = 3; public static final int DEFAULT_FILES_ASYNC_UPLOAD_EXECUTOR_MAX_THREADS = 6; public static final int DEFAULT_DEPLOY_FROM_URL_EXECUTOR_MAX_THREADS = 26; + public static final Integer DEFAULT_CLOUD_LOGGING_EXECUTOR_CORE_THREADS = 4; + public static final Integer DEFAULT_CLOUD_LOGGING_EXECUTOR_MAX_THREADS = 8; + public static final Integer DEFAULT_CLOUD_LOGGING_EXECUTOR_QUEUE_CAPACITY = 128; public static final boolean DEFAULT_ENABLE_ON_START_FILES_WITHOUT_CONTENT_CLEANER = false; public static final int DEFAULT_THREADS_FOR_FILE_UPLOAD_TO_CONTROLLER = 6; public static final int DEFAULT_THREADS_FOR_FILE_STORAGE_UPLOAD = 7; @@ -230,6 +236,9 @@ public class ApplicationConfiguration { private Integer springSchedulerTaskExecutorThreads; private Integer filesAsyncUploadExecutorThreads; private Integer deployFromUrlExecutorMaxThreads; + private Integer cloudLoggingExecutorCoreThreads; + private Integer cloudLoggingExecutorMaxThreads; + private Integer cloudLoggingExecutorQueueCapacity; private Boolean isOnStartFilesWithoutContentCleanerEnabledThroughEnvironment; private Integer threadsForFileUploadToController; private Integer threadsForFileStorageUpload; @@ -292,6 +301,9 @@ public void load() { getAbortedOperationsTtlInSeconds(); getFilesAsyncUploadExecutorMaxThreads(); getDeployFromUrlExecutorMaxThreads(); + getCloudLoggingExecutorCoreThreads(); + getCloudLoggingExecutorMaxThreads(); + getCloudLoggingExecutorQueueCapacity(); getObjectStoreRegions(); } @@ -445,6 +457,27 @@ public Integer getDeployFromUrlExecutorMaxThreads() { return deployFromUrlExecutorMaxThreads; } + public Integer getCloudLoggingExecutorCoreThreads() { + if (cloudLoggingExecutorCoreThreads == null) { + cloudLoggingExecutorCoreThreads = getCloudLoggingExecutorCoreThreadsFromEnvironment(); + } + return cloudLoggingExecutorCoreThreads; + } + + public Integer getCloudLoggingExecutorMaxThreads() { + if (cloudLoggingExecutorMaxThreads == null) { + cloudLoggingExecutorMaxThreads = getCloudLoggingExecutorMaxThreadsFromEnvironment(); + } + return cloudLoggingExecutorMaxThreads; + } + + public Integer getCloudLoggingExecutorQueueCapacity() { + if (cloudLoggingExecutorQueueCapacity == null) { + cloudLoggingExecutorQueueCapacity = getCloudLoggingExecutorQueueCapacityFromEnvironment(); + } + return cloudLoggingExecutorQueueCapacity; + } + public String getGlobalAuditorUser() { if (globalAuditorUser == null) { globalAuditorUser = getGlobalAuditorUserFromEnvironment(); @@ -932,6 +965,27 @@ private Integer getDeployFromUrlExecutorMaxThreadsFromEnvironment() { return value; } + private Integer getCloudLoggingExecutorCoreThreadsFromEnvironment() { + Integer value = environment.getPositiveInteger(CFG_CLOUD_LOGGING_EXECUTOR_CORE_THREADS, + DEFAULT_CLOUD_LOGGING_EXECUTOR_CORE_THREADS); + logEnvironmentVariable(CFG_CLOUD_LOGGING_EXECUTOR_CORE_THREADS, Messages.CLOUD_LOGGING_EXECUTOR_CORE_THREADS, value); + return value; + } + + private Integer getCloudLoggingExecutorMaxThreadsFromEnvironment() { + Integer value = environment.getPositiveInteger(CFG_CLOUD_LOGGING_EXECUTOR_MAX_THREADS, + DEFAULT_CLOUD_LOGGING_EXECUTOR_MAX_THREADS); + logEnvironmentVariable(CFG_CLOUD_LOGGING_EXECUTOR_MAX_THREADS, Messages.CLOUD_LOGGING_EXECUTOR_MAX_THREADS, value); + return value; + } + + private Integer getCloudLoggingExecutorQueueCapacityFromEnvironment() { + Integer value = environment.getPositiveInteger(CFG_CLOUD_LOGGING_EXECUTOR_QUEUE_CAPACITY, + DEFAULT_CLOUD_LOGGING_EXECUTOR_QUEUE_CAPACITY); + logEnvironmentVariable(CFG_CLOUD_LOGGING_EXECUTOR_QUEUE_CAPACITY, Messages.CLOUD_LOGGING_EXECUTOR_QUEUE_CAPACITY, value); + return value; + } + private String getGlobalAuditorUserFromEnvironment() { String value = environment.getString(CFG_GLOBAL_AUDITOR_USER); return value; diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/configuration/AsyncProcessLoggerConfiguration.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/configuration/AsyncProcessLoggerConfiguration.java index b69cb1c2e4..a40274c61c 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/configuration/AsyncProcessLoggerConfiguration.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/configuration/AsyncProcessLoggerConfiguration.java @@ -1,6 +1,7 @@ package org.cloudfoundry.multiapps.controller.web.configuration; import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; import jakarta.inject.Inject; import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration; @@ -25,4 +26,18 @@ public Executor getAsyncExecutor() { executor.initialize(); return executor; } + + @Bean("cloudLoggingAsyncExecutor") + public Executor getCloudLoggingAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(configuration.getCloudLoggingExecutorCoreThreads()); + executor.setMaxPoolSize(configuration.getCloudLoggingExecutorMaxThreads()); + executor.setQueueCapacity(configuration.getCloudLoggingExecutorQueueCapacity()); + // Log export is best-effort and must never fail a deployment; when the pool and + // queue are saturated, run the task on the caller thread instead of aborting it. + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.setThreadNamePrefix("cloud-logging-export-"); + executor.initialize(); + return executor; + } }