Skip to content

With virtual threads enabled, long-running fixedDelay tasks block fixedRate tasks #33408

@kzander91

Description

@kzander91

Framework: 6.1.11
Boot: 3.3.2
Reproducer: demo.zip

As discussed in #31900 and documented in the reference docs, with virtual threads enabled, fixedDelay tasks run on a single thread. However, a long-running fixedDelay task also blocks concurrent fixedRate tasks. This behaviour isn't documented and not obvious (to me at least), so I would consider this a bug.

Consider the following app:

@EnableScheduling
@SpringBootApplication
public class DemoApplication {

    private static final Logger log = LoggerFactory.getLogger(DemoApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Scheduled(initialDelay = 10000, fixedDelay = 10000)
    public void fixedDelay() {
        log.info("fixedDelay start: Blocks concurrent fixedRate tasks");
        long start = System.nanoTime();
        while ((System.nanoTime() - start) < TimeUnit.SECONDS.toNanos(10L)) {
            // busy work
        }
        log.info("fixedDelay end, unblocking fixedRate tasks");
    }

    @Scheduled(fixedRate = 1000)
    public void fixedRate() {
        log.info("fixedRate");
    }

}

This prints:

2024-08-19T17:32:40.727+02:00  INFO 39220 --- [demo] [   scheduling-2] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:41.722+02:00  INFO 39220 --- [demo] [   scheduling-3] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:42.717+02:00  INFO 39220 --- [demo] [   scheduling-4] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:43.717+02:00  INFO 39220 --- [demo] [   scheduling-5] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:44.718+02:00  INFO 39220 --- [demo] [   scheduling-6] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:45.719+02:00  INFO 39220 --- [demo] [   scheduling-7] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:46.717+02:00  INFO 39220 --- [demo] [   scheduling-8] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:47.717+02:00  INFO 39220 --- [demo] [   scheduling-9] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:48.718+02:00  INFO 39220 --- [demo] [  scheduling-10] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:49.719+02:00  INFO 39220 --- [demo] [  scheduling-11] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:50.718+02:00  INFO 39220 --- [demo] [  scheduling-12] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:32:50.720+02:00  INFO 39220 --- [demo] [   scheduling-1] com.example.demo.DemoApplication         : fixedDelay start: Blocks concurrent fixedRate tasks
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [   scheduling-1] com.example.demo.DemoApplication         : fixedDelay end, unblocking fixedRate tasks
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-13] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-16] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-14] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-17] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-19] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-15] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-20] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-21] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-22] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:00.721+02:00  INFO 39220 --- [demo] [  scheduling-18] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:01.718+02:00  INFO 39220 --- [demo] [  scheduling-23] com.example.demo.DemoApplication         : fixedRate
2024-08-19T17:33:02.718+02:00  INFO 39220 --- [demo] [  scheduling-24] com.example.demo.DemoApplication         : fixedRate
  • The app starts and prints "fixedRate" every second, as expected.
  • After 10 seconds, the fixedDelay task kicks in and performs some work for 10 seconds. While that's going on, no further fixedRate tasks are run.
  • Finally, after 10 seconds of work, the fixedDelay task completes and we get a bunch of "fixedRate" messages again. Then, we continue with the regular schedule of one message per second.

While debugging this, I found that the SimpleAsyncTaskScheduler that is used under the covers uses its first thread, scheduling-1, both to run the fixedDelay task, and to schedule the fixedRate tasks. This means if scheduling-1 is busy running a task, it can't submit new fixedRate tasks for execution.

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions