Hi,
It could be because of any of the 2 reasons:
- App Context getting loaded twice, or
- You have multiple app instances running (for scaling purposes).
For 1), you may follow any of the above answers. I will speak about (2).
For (2), Generally, In cloud environments, you would have multiple instances (like 2,3,4....) running in cloud. Hence, your scheduler will be triggered by each app instance.
I have faced this issue in cloud environment too. We run our app on Cloud Foundry and we have scaled to 2 instances of our app. Our scheduler started triggering twice (from each of the app instance i.e. app_instance_0 and app_instance_1).
In order to overcome, we could do any one of the below:
APPROACH I:
Use System.getenv("CF_INSTANCE_INDEX");
// this var is provided by default to the app by cloud foundry as env variable.
it gives us the app instance index which triggered the method call. Hence, we can then use simple condition to alwys trigger schduler when app_instance_0 runs it using:
@Scheduled(cron = * * * * * *)
public void scheduledTask() {
String appInstanceIndex = System.getenv("CF_INSTANCE_INDEX");
if (appInstanceIndex.equals("0")) {
.... //your scheduling logic here
.... //your scheduling logic here
}
else {
//dont do anything as its call from other app instances...
}
}
One main advantage here is that we dont make any DB calls. Ofcourse it wont work if you dont use CF. But do check if your PaaS provides any such variable.
APPROACH II:
This is a genric approach. Implement a new table for scheduler. Add a unique constraint column. In your shceduler method, generate today's date and add it into Db. (this date is saved in table with column having unique constraint). Now, first time always this scheduler will run properly. When other app instances try to create todays date again and save into DB, it will lead to exception as DB has unique constraint and it cant add the date again. hence, for other app instances, the scheduler logic will fail and lead to exception.
@Scheduled(cron = * * * * * *)
public void scheduledTask() {
String date = LocalDate.now().toString();
try{
insertDateInDb();
// your scheduler logic here
}
catch(Exception e){
// Dont do anything...
}
}