0

I have a Problem with asynchronous methods that run on a customTaskExecutors. In the run method I never reach the last log.info that the thread is finished running (where I would usualy put other cleanup code). I would like to stop that thread in the PreDestroy method with setting the boolean to false, but pre destroy only gets called when spring has ended all his threads, which includes the customTaskExecutor. I already have put the custom Exectur with a short awaitTermination time, didn't change anything. I also made a class, where I wire all taskExecutors in and shut them down externaly. That all stops the ThreadExecutor but never in a way where I can have code after the while loop running.

Does anybody have a best practice for what i want to do (basically change the boolean for the while loop on sigterm signal)? Or am I bound to use PreDestroy for all cleanup stuff when I want to use TaskExecutors of Spring Boot?

@PreDestroy
public void shutDown() {
    log.info("Shutting down AsyncRunner...");
    printingRunning = false;
}

@Override
@Async("customTaskExecutor")  // Using the custom executor from AsyncConfig
public void run(String... args) throws Exception {
    log.info("AsyncRunner starting on thread: {}", Thread.currentThread().getName());

    try {
        while(printingRunning && !Thread.currentThread().isInterrupted()) {
            Thread.sleep(1000);
            this.printWorkOut();
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt(); // Restore interrupted status
        log.info("AsyncRunner was interrupted.");
    }

    log.info("AsyncRunner finished on thread: {}", Thread.currentThread().getName());
}
1
  • Feels like a wrong design to start with. You shouldn't do a Thread.sleep in an async task, as that will block a thread. If you are using that task executor for more things you will run out of threads or even worse have a non responsive system. Looks like you would need a scheduler instead of an async task and trigger the method each 1 second. Commented Oct 30 at 15:15

1 Answer 1

1
  1. Use a volatile flag to control the loop.

  2. Register a shutdown hook to set the flag.

  3. Ensure the thread checks the flag and exits cleanly.

  4. Avoid relying solely on @PreDestroy for thread control.

@Component
public class AsyncRunner implements CommandLineRunner {

    private volatile boolean printingRunning = true;

    @Autowired
    private TaskExecutor customTaskExecutor;

    @Override
    public void run(String... args) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.info("Shutdown hook triggered. Stopping AsyncRunner...");
            printingRunning = false;
        }));

        customTaskExecutor.execute(() -> {
            log.info("AsyncRunner starting on thread: {}", Thread.currentThread().getName());

            try {
                while (printingRunning && !Thread.currentThread().isInterrupted()) {
                    Thread.sleep(1000);
                    printWorkOut();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.info("AsyncRunner was interrupted.");
            }

            log.info("AsyncRunner finished on thread: {}", Thread.currentThread().getName());
            // Cleanup logic here
        });
    }

    private void printWorkOut() {
        log.info("Working out...");
    }
}
``
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.