Small Java and SpringBoot question please.
I would like to build an endpoint, which when a client calls in, will return immediately, but after a minute from the call, will trigger a job.
I have no control over when the client triggers the requests, I cannot hold the client for that time, and I have no control over the client at all.
Basically, I would like to achieve something like this:
@GetMapping(path = "/triggerJobMinuteLaterButReturnImmediately") public String triggerJobMinuteLaterButReturnImmediately() { invokeThisMethodOneMinuteLater(); return "jobTriggered"; }
What I tried so far, is to come up with a code like this:
@GetMapping(path = "/triggerJobMinuteLaterButReturnImmediately") public String triggerJobMinuteLaterButReturnImmediately() { try { Thread.sleep(60000); invokeThisMethodOneMinuteLater(); } catch (InterruptedException e) { e.printStackTrace(); } return "jobTriggered"; }
This works in terms of triggering the job one minute later, happy, but I am not returning immediately, I am holding the client during all that time.
May I ask how to achieve the trigger of the job, minute later from the client http call, but able to return a response immediately to the client please?
Thank you
Advertisement
Answer
You definetely don’t want to use Thread.sleep
. In this case, you’re keeping the connection open for 60 seconds. If user closes the browser tab, it may result in error.
The better option is to apply ScheduledExecutorService
.
class AsyncConfig { @Bean public ScheduledExecutorService scheduledExecutorService() { // number of threads should be tuned with a property return Executors.newScheduledThreadPool(threadNum); } } @RestController class SomeController { @Autowired private ScheduledExecutorService scheduler; @GetMapping(path = "/triggerJobMinuteLaterButReturnImmediately") public String triggerJobMinuteLaterButReturnImmediately() { scheduler.schedule(() -> invokeThisMethodOneMinuteLater(), 1, TimeUnit.MINUTES); return "jobTriggered"; } }
Now a user gets response immediately while job is being scheduled.
Nevertheless, this approach is not perfect either. The service can crash after the job has been successfully registered. So, it won’t be invoked eventually. If you want to overcome this obstacle, you should store the job info in some external storage (e.g. relational database). And then check it periodically, execute it, and mark as done.