Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SimpleAsyncTaskScheduler: Returned ScheduledFuture does not track provided task execution #32589

Closed
Sheikah45 opened this issue Apr 8, 2024 · 0 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: documentation A documentation task
Milestone

Comments

@Sheikah45
Copy link

Affects: Spring Framework 6.1.5

The ScheduledFuture returned by SimpleAsyncTaskScheduler does not track the execution state of the submitted task, but rather tracks the execution state of the scheduling of the task. This is a noted difference from the ThreadPoolTaskScheduler where the returned ScheduledFuture tracks the execution of the submitted task itself.

This has consequences for anyone migrating their taskScheduler to use virtual threads and currently interact with the returned future, since SimpleAsyncTaskScheduler is the recommended class to do so.

From my investigation this is caused by the wrapping of the provided task into a delegate task which submits the provided task to the underlying SimpleAsyncTaskExecutor execute method. This delegation effectively hides the execution of the provided task from the ScheduledExecutorService meaning once the task is submitted to the underlying execute method it is no longer able to track the status of the task execution and sets its state to success.

Below I have included some test cases that demonstrate the effects of this in both the successful and exceptional cases. They can also be found in the following repo https://github.com/Sheikah45/TaskSchedulerExample

If it is not possible to allow the delegating task status to be tracked I would suggest adding a note to the documentation of the SimpleAsyncTaskScheduler to make it clear what the expected behavior of the returned Scheduled future is, since as it stands now the behavior appears to contradict the documentation of the schedule methods which state: Returns: a ScheduledFuture representing pending completion of the task

    @Test
    void tracksSchedulingOfTask() throws Exception {
        AtomicBoolean atomicBoolean = new AtomicBoolean(false);
        SimpleAsyncTaskScheduler taskScheduler = new SimpleAsyncTaskScheduler();
        ScheduledFuture<?> future = taskScheduler.schedule(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            atomicBoolean.set(true);
        }, Instant.now().plusSeconds(1));

        future.get();

        assertTrue(atomicBoolean.get());
    }

    @Test
    void tracksExecutionTask() throws Exception {
        AtomicBoolean atomicBoolean = new AtomicBoolean(false);
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.initialize();
        ScheduledFuture<?> future = taskScheduler.schedule(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            atomicBoolean.set(true);
        }, Instant.now().plusSeconds(1));

        future.get();

        assertTrue(atomicBoolean.get());
    }

    @Test
    void doesNotThrowTaskException() throws Exception {
        SimpleAsyncTaskScheduler taskScheduler = new SimpleAsyncTaskScheduler();
        ScheduledFuture<?> schedule = taskScheduler.schedule(() -> {
            throw new RuntimeException();
        }, Instant.now().plusSeconds(1));

        assertThrows(ExecutionException.class, schedule::get);
    }

    @Test
    void throwsTaskException() throws Exception {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.initialize();
        ScheduledFuture<?> schedule = taskScheduler.schedule(() -> {
            throw new RuntimeException();
        }, Instant.now().plusSeconds(1));

        assertThrows(ExecutionException.class, schedule::get);
    }
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Apr 8, 2024
@jhoeller jhoeller added type: documentation A documentation task in: core Issues in core modules (aop, beans, core, context, expression) and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Apr 8, 2024
@jhoeller jhoeller self-assigned this Apr 8, 2024
@jhoeller jhoeller added this to the 6.1.6 milestone Apr 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: documentation A documentation task
Projects
None yet
Development

No branches or pull requests

3 participants