Making @Schedule run only once in a clustered environment
Asked Answered
X

3

6

I have two tomee instances clustered.

Each one have a method annotated like

@Schedule(dayOfWeek = "*")
public void runMeDaily() {...}

I'd like to run this method only once a day. Not twice a day (one on each instance)

I could use a flag as described here Run @Scheduled task only on one WebLogic cluster node? or just elect some node, but I wonder if there's a more elegant way to do that.

This question is somewhat related to EJB3.1 @Schedule in clustered environment but I am not using JBOSS. (and it's not answered)

Xenocryst answered 16/10, 2014 at 10:58 Comment(1)
X
1

I could only solve this using a non-Java EE solution, specific to the platform (proprietary). In my case, I am using TomEE+ and Quartz. Running Quartz in the clustered mode (org.quartz.jobStore.isClustered = true) and persisting the timers in a single database forces Quartz to choose an instance to trigger the timer, so it will only run once.

This link was very useful -- http://rmannibucau.wordpress.com/2012/08/22/tomee-quartz-configuration-for-scheduled-methods/

It's a shame Java EE does not specify a behavior for that. (yet, I hope) :-)

Xenocryst answered 2/1, 2015 at 17:27 Comment(0)
A
2

Im using same approach as in other thread - checking that particular host is the correct one to run job. But..

Im not very info ee tools, but in spring you can use profiles for that. Probably you can find similar solution for your needs. Take a look at http://spring.io/blog/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles

You can define two seperate beans:

@Configuration
@Profile("dev")
public class StandaloneDataConfig {

@Bean
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.HSQL)
        .addScript("classpath:com/bank/config/sql/schema.sql")
        .addScript("classpath:com/bank/config/sql/test-data.sql")
        .build();
}
}

@Configuration
@Profile("production")
public class JndiDataConfig {

@Bean
public DataSource dataSource() throws Exception {
    Context ctx = new InitialContext();
    return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}

and decide which one to turn on by switching profile. So your class with method annotated @Scheduled would be loaded only for specific profile. Ofcourse then you need to configure your app to turn on profile on of the nodes only. In spring app it would be as simple as passing -Dspring.profiles.active=profile to one of them.

Azurite answered 16/10, 2014 at 11:29 Comment(2)
great idea, I'll take a look on it :-) I am afraid I can't switch to spring in this project right now, but I'll certainly consider your option in the next one. thx!Xenocryst
as I said, you can probably find something similar in ejb.Azurite
X
1

I could only solve this using a non-Java EE solution, specific to the platform (proprietary). In my case, I am using TomEE+ and Quartz. Running Quartz in the clustered mode (org.quartz.jobStore.isClustered = true) and persisting the timers in a single database forces Quartz to choose an instance to trigger the timer, so it will only run once.

This link was very useful -- http://rmannibucau.wordpress.com/2012/08/22/tomee-quartz-configuration-for-scheduled-methods/

It's a shame Java EE does not specify a behavior for that. (yet, I hope) :-)

Xenocryst answered 2/1, 2015 at 17:27 Comment(0)
B
-1

I solved this problem by making one of the box as master. basically set an environment variable on one of the box like master=true.

and read it in your java code through system.getenv("master"). if its present and its true then run your code.

basic snippet

@schedule()
void process(){
boolean master=Boolean.parseBoolean(system.getenv("master"));
if(master)
{
   //your logic
}

}
Baculiform answered 2/1, 2015 at 8:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.