Amit
Amit

Reputation: 656

Perform a task in spring after application context start so that task failure wont affect application start

I have a task that i need to perform at the time of application startup in spring (context start). There were cases when that task can fail (data may not be ready) and its causing the application start to fail. My question is :

  1. What is the best way to do it so that task success/failure wont affect the start? Note : The case is that we have to run the task at-least once after start of context?

Upvotes: 1

Views: 1767

Answers (3)

Amit
Amit

Reputation: 656

What @Angelo provided can work too. I am going with following. Which will be running this task after context refresh/start is done.
@Scheduled(cron="*/5 * * * * MON-FRI") public void doSomething() { // something that should execute on weekdays only }

NOTE: The requirement changed a bit where i have to do this task everyday at-least once hence using @Scheduled

Upvotes: 1

Tobb
Tobb

Reputation: 12225

A bit hacky, but might do the trick:

@Component
public class SomeBean {

    @PostConstruct
    public void doTask() {
       int i = 0;
        try {
            doTheTask();
        } catch (final Exception e) {
            if (i == 10) {
                throw new RuntimeException(e);
            }
            Thread.sleep(200);
            i++;
        }
    }
}

This will run the task 10 times before giving up, waiting 200ms between each attempt. Note that if the same thread that is being put to sleep here is used to ready the data, it won't help, you would have to put the running of the task in a separate thread.

Another possibility is using Spring's @Scheduled:

First, you need to enable scheduling. This is done either by the @EnableScheduling in your java config, or with some xml:

<task:scheduled-tasks scheduler="myScheduler">
    <task:scheduled ref="myBean" method="printMessage" fixed-delay="5000" />
</task:scheduled-tasks>

<task:scheduler id="myScheduler"/>   

Next, annotate the method with @Scheduled:

@Scheduled(initialDelay= 600000) //ms, =10 minutes
public void doTask() {
   doTheTask();
}

Note that there is still no guarantee for the task actually succeeding. You could combine it fixedDelay to run it multiple times, but note that any exception thrown out of the method will halt the series of execution. For a more guaranteed run-approach, something like this should work (looks a bit odd with throwing exception on success though..)

//numbers in ms, 10 minutes before the first run, then a new attempt every minute
@Scheduled(initialDelay= 600000, fixedDelay = 60000) 
public void doTask() {
   try {
      doTheTask();
   } catch (final Exception e) {
       //do nothing, retry in 1 minute
       return;
   }
   trow new AbortScheduledException("Task complete"); //made up exception with descriptive name..
}

Upvotes: 0

Angelo Immediata
Angelo Immediata

Reputation: 6954

You may create a spring component listening for the spring context started event. Something like this:

@Component
public class SpringCtxListener {

    @EventListener
    public void checkUser(ContextRefreshedEvent cre) throws Exception
    {
        //This method is called when Spring context has started and here you can execute your task
    }
}

Angelo

Upvotes: 3

Related Questions