Open csdbianhua opened 3 years ago
So maybe we can wrap every
ThreadPoolTaskExecutor
I don't think this is possible. Once wrapped, a ThreadPoolTaskExecutor
would become an Executor
which would require changing the bean's type. This would break anyone who was trying to inject it as a more specific type.
To do something here, I think we might need a way to customize things when ThreadPoolTaskExecutor
is initializing its executor in initializeExecutor
. Perhaps @snicoll has a better idea.
Certainly we need to be able to customize the way the executor is created, and that would require a framework change. The current API has a TaskDecorator
that we might be able to use alongside TimedRunnable
that's package private at the moment.
Another solution would be to provide this feature in the framework API itself and relying on it to decorate the executor accordingly.
This would break anyone who was trying to inject it as a more specific type.
I agree this is indeed a problem, generally. But when it comes to a specific case like 'ThreadPoolTaskExecutor', I'd think injecting it as an Executor is better in terms of design. (And I have to admit this is NOT a reason to enforce all users to accept it.)
Comparing with writing a lot of code to setup a monitor against ThreadPoolTaskExecutor by myself, only to maintain the ability to inject it as a specific type, which by itself a design smell, I'd rather having an automatic way to setup it all, and also stop me from 'programming to concrete class.'
It makes it a lot easier to go along with the right way, and makes the smelly way harder.
Of course, another way of doing it, is to change how the ExectuterServiceMetrcis#monitor
was implemented.
ExectuterServiceMetrcis#monitor
can work with any Executor
or ExecutorService
,
Can we make the TaskExecutorMetricsAutoConfiguration to bind against all ExecutorService
?
By changing
public void bindTaskExecutorsToRegistry(Map<String, Executor> executors, MeterRegistry registry) {
executors.forEach((beanName, executor) -> {
if (executor instanceof ThreadPoolTaskExecutor) {
monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskExecutor) executor),
() -> getTaskExecutorName(beanName));
}
else if (executor instanceof ThreadPoolTaskScheduler) {
monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskScheduler) executor),
() -> getTaskSchedulerName(beanName));
}
});
}
to something like:
public void bindTaskExecutorsToRegistry(Map<String, Executor> executors, MeterRegistry registry) {
executors.forEach((beanName, executor) -> {
if (executor instanceof ThreadPoolTaskExecutor) {
monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskExecutor) executor),
() -> getTaskExecutorName(beanName));
}
else if (executor instanceof ThreadPoolTaskScheduler) {
monitor(registry, safeGetThreadPoolExecutor((ThreadPoolTaskScheduler) executor),
() -> getTaskSchedulerName(beanName));
} else if (executor instanceof ExecutorService) {
new ExecutorServiceMetrics((ExecutorService) executor, beanName, Collections.emptyList()).bindTo(registry);
}
});
}
Thanks for the suggestion, @hugogu. I think it would be confusing for TaskExecutorMetricsAutoConfiguration
to bind metrics for all ExecutorService
beans and not just those used for task execution.
Thanks for the suggestion, @hugogu. I think it would be confusing for
TaskExecutorMetricsAutoConfiguration
to bind metrics for allExecutorService
beans and not just those used for task execution.
Yes, and I assume the confusion can hopefully be reduced a bit when the class was named ExecutorMetricsAutoConfiguration
and moved out of the task
package.
Hmm, was it really about the scope of spring-boot
project? Since it is called spring-boot, not Java-boot, then it makes a lot sense to only support TaskExecutor instead of all Executors.
Description: I need to expose task execution time and idle time metrics of ‘ThreadPoolTaskExecutor’. After few tasks being executed, all metrics except those two show up. I found that TaskExecutorMetricsAutoConfiguration's behavior is iterating over
ThreadPoolTaskExecutor
s and invokingExecutorServiceMetrics#monitor
. It do can register "executor.active", "executor.completed" and other metrics, but "executor"(task execution time) and "executor.idle"(task idle time) which processing in TimedExecutorService are left out.Expectation: As I mentioned in #23818, I need to use the TimedExecutorService returned by
ExecutorServiceMetrics#monitor
to wrap the tasks I submitted, then I can get task execution time and idle time. So maybe we can wrap everyThreadPoolTaskExecutor
, then task execution time and idle time should be recorded properly.Version: 2.6.0-SNAPSHOT
Sample: pom.xml
ThreadPoolMetricsDemoApplication.java