-
Couldn't load subscription status.
- Fork 38.8k
Closed
Labels
in: coreIssues in core modules (aop, beans, core, context, expression)Issues in core modules (aop, beans, core, context, expression)type: regressionA bug that is also a regressionA bug that is also a regression
Milestone
Description
Since Spring 6.2.0 functionality to specify custom scheduler for @Scheduled annotation is not working anymore.
Minimal reproducible example:
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskHolder;
import org.springframework.scheduling.config.TaskSchedulerRouter;
class SchedulerConfigTest {
@Test
void withQualifiedScheduler() throws Exception {
var ctx = new AnnotationConfigApplicationContext(QualifiedExplicitSchedulerConfig.class);
assertThat(ctx.getBean(ScheduledTaskHolder.class).getScheduledTasks()).hasSize(2);
Thread.sleep(110);
assertThat(ctx.getBean("defaultSchedulerThreads", Set.class))
.hasSizeGreaterThanOrEqualTo(1).allMatch(e -> ((String) e).startsWith("taskScheduler-"));
assertThat(ctx.getBean("explicitSchedulerThreads", Set.class))
.hasSizeGreaterThanOrEqualTo(1).allMatch(e -> ((String) e).startsWith("customScheduler-"));
}
@TestConfiguration
@EnableScheduling
static class QualifiedExplicitSchedulerConfig {
public static final String DEFAULT_TASK_SCHEDULER_BEAN_NAME = TaskSchedulerRouter.DEFAULT_TASK_SCHEDULER_BEAN_NAME;
public static final String CUSTOM_TASK_SCHEDULER_BEAN_NAME = "customTaskScheduler";
@Bean
public Set<String> defaultSchedulerThreads() {
return new HashSet<>();
}
@Bean
public Set<String> explicitSchedulerThreads() {
return new HashSet<>();
}
@Bean(name = DEFAULT_TASK_SCHEDULER_BEAN_NAME)
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setThreadNamePrefix("taskScheduler-");
return taskScheduler;
}
@Bean(name = CUSTOM_TASK_SCHEDULER_BEAN_NAME)
public SimpleAsyncTaskScheduler customTaskScheduler() {
SimpleAsyncTaskScheduler taskScheduler = new SimpleAsyncTaskScheduler();
taskScheduler.setThreadNamePrefix("customScheduler-");
return taskScheduler;
}
@Scheduled(fixedRate = 10)
public void task() throws Exception {
defaultSchedulerThreads().add(Thread.currentThread().getName());
}
@Scheduled(fixedRate = 10, scheduler = CUSTOM_TASK_SCHEDULER_BEAN_NAME)
public void taskWithExplicitScheduler() throws Exception {
explicitSchedulerThreads().add(Thread.currentThread().getName());
}
}
}I believe this happened in this commit dc2c8d60. Now Runnable is wrapped into OutcomeTrackingRunnable. As result TaskSchedulerRouter fails to determine qualifier:
protected String determineQualifier(Runnable task) {
return (task instanceof SchedulingAwareRunnable sar ? sar.getQualifier() : null);
}since OutcomeTrackingRunnable is not implementing SchedulingAwareRunnable.
@bclozel, do you think it makes sense for OutcomeTrackingRunnable to implement SchedulingAwareRunnable interface instead of Runnable? Or to have two flavours of OutcomeTrackingRunnable? And Task will wrap underlying runnable depends on underlying task?
Smth like:
public Task(Runnable runnable) {
Assert.notNull(runnable, "Runnable must not be null");
if (runnable instanceof SchedulingAwareRunnable sar) {
this.runnable = new OutcomeTrackingSchedulingAwareRunnable(runnable);
} else {
this.runnable = new OutcomeTrackingRunnable(runnable);
}
this.lastExecutionOutcome = TaskExecutionOutcome.create();
}Metadata
Metadata
Assignees
Labels
in: coreIssues in core modules (aop, beans, core, context, expression)Issues in core modules (aop, beans, core, context, expression)type: regressionA bug that is also a regressionA bug that is also a regression