11package ch.derlin.bbdata
22
3+ import io.swagger.v3.oas.annotations.Hidden
4+ import io.swagger.v3.oas.annotations.Operation
35import org.slf4j.Logger
46import org.slf4j.LoggerFactory
57import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler
68import org.springframework.beans.factory.annotation.Value
9+ import org.springframework.boot.actuate.endpoint.annotation.ReadOperation
10+ import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint
711import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
812import org.springframework.boot.task.TaskExecutorCustomizer
913import org.springframework.context.annotation.Configuration
14+ import org.springframework.core.task.TaskExecutor
1015import org.springframework.scheduling.annotation.AsyncConfigurer
1116import org.springframework.scheduling.annotation.EnableAsync
1217import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
@@ -45,7 +50,7 @@ class AsyncExecutorCustomizer : TaskExecutorCustomizer {
4550 }
4651}
4752
48- @ConditionalOnProperty(" async.enabled " , havingValue = " true" , matchIfMissing = true )
53+ @ConditionalOnProperty(AsyncProperties . ENABLED , havingValue = " true" , matchIfMissing = true )
4954@EnableAsync
5055@Configuration
5156class AsyncConfig : AsyncConfigurer {
@@ -66,4 +71,29 @@ class AsyncExceptionHandler : AsyncUncaughtExceptionHandler {
6671 val niceParams = params.take(2 ).joinToString(" ," ) { it.toString() }
6772 logger.error(" in ${method.name} with ${params.size} params: $niceParams ..." , throwable)
6873 }
74+ }
75+
76+ @Component
77+ @ConditionalOnProperty(AsyncProperties .ENABLED , havingValue = " true" , matchIfMissing = true )
78+ @WebEndpoint(id = " tasks" )
79+ class AsyncMonitor (private val taskExecutor : TaskExecutor ? = null ) {
80+ /* * add an optional tasks actuator to monitor async executor (hidden) */
81+
82+ @ReadOperation
83+ @Operation(description = " Actuator web endpoint 'tasks', monitor async tasks execution" )
84+ @Hidden
85+ fun executorInfo (): Map <String , Any > {
86+ // use linkedMap to preserve insertion order in output
87+ val executorInfo = linkedMapOf<String , Any >()
88+ val tasksInfo = linkedMapOf<String , Any >()
89+ if (taskExecutor is ThreadPoolTaskExecutor )
90+ taskExecutor.threadPoolExecutor.let {
91+ executorInfo[" pool-size" ] = it.corePoolSize
92+ executorInfo[" active-count" ] = it.activeCount
93+ executorInfo[" queue-size" ] = it.queue.size
94+ tasksInfo[" task-count" ] = it.taskCount
95+ tasksInfo[" completed-task-count" ] = it.completedTaskCount
96+ }
97+ return linkedMapOf(" executor" to executorInfo, " tasks" to tasksInfo)
98+ }
6999}
0 commit comments