TaskDecorator doesn't directly work with task scheduler implementations - ThreadPoolTaskScheduler/ConcurrentTaskScheduler.

Related: https://github.com/spring-projects/spring-framework/issues/18502

I think the underlying reason is there is no easy way of applying TaskDecorator to ScheduledExecutorService.

Currently, I workaround by wrapping ScheduledExecutorService with a proxy that performs task decoration.

Proxy Handler:

public class TaskDecoratingScheduledExecutorServiceInterceptor implements MethodInterceptor {

    private final TaskDecorator taskDecorator;

    public TaskDecoratingScheduledExecutorServiceInterceptor(TaskDecorator taskDecorator) {
        this.taskDecorator = taskDecorator;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object[] args = invocation.getArguments();
        if (args.length == 0) {
            return invocation.proceed();  // no decoration, simply proceed
        }

        Object swapped;
        if (args[0] instanceof Runnable) {
            swapped = replaceRunnable(method, (Runnable) args[0]);
        } else if (args[0] instanceof Callable) {
            swapped = replaceCallable(method, (Callable) args[0]);
        } else if (args[0] instanceof Collection) { // see the ExecutorService API
            swapped = ((Collection<? extends Callable<?>>) args[0]).stream()
                    .map(callable -> replaceCallable(method, callable))
                    .collect(toList());
        } else {
            return invocation.proceed(); // bail out, no replace needed
        }
        args[0] = swapped;  // swap

        return invocation.proceed();
    }

    ....
}

Wrap created ScheduledThreadPoolExecutor in ThreadPoolTaskScheduler:

ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler() {

    private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;

    @Override
    protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {

        // keep it for "getScheduledThreadPoolExecutor()"
        this.scheduledThreadPoolExecutor = (ScheduledThreadPoolExecutor) super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler);

        ScheduledExecutorService executorService = this.scheduledThreadPoolExecutor;

        // apply task decorator via proxy
        ProxyFactory proxyFactory = new ProxyFactory(executorService);
        proxyFactory.addAdvice(new TaskDecoratingScheduledExecutorServiceInterceptor(taskDecorator));

        return (ScheduledExecutorService) proxyFactory.getProxy();
    }

    @Override
    public ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() throws IllegalStateException {
        return this.scheduledThreadPoolExecutor;
    }
}

I think it would be nice that ThreadPoolTaskScheduler/ConcurrentTaskScheduler to have some API to work with TaskDecorator OR a way to easily customize underlying ScheduledExecutorService to apply decorators.

For example, a delegate class that takes TaskDecorator:

public class TaskDecoratingScheduledExecutorServiceDelegate implement ScheduledExecutorService {
  private final ScheduledExecutorService delegate;
  private final TaskDecorator taskDecorator;

  ...
}

Comment From: osamucamarques

It would be great!

Comment From: osamucamarques

till now I handle it like this:

Spring TaskScheduler does not work with TaskDecorator

Comment From: jhoeller

On a similar note as with #32460, this is actually an area of inconsistency as of 6.1 since the new SimpleAsyncTaskScheduler comes with inherited TaskDecorator support from SimpleAsyncTaskExecutor. Even ConcurrentTaskScheduler comes with some TaskDecorator support from its ConcurrentTaskExecutor base class but does not apply it to scheduler operations, just to the inherited executor operations. We'll make this as consistent as possible for 6.2.