Hi well, now I really have some doubts.
I've noticed that in 1.6.0.2 the timers weren't ok, so I've switched to the latest 1.7.0. It seems that from 1.7.0, quartz packages now belong to the apache domain, so the application.properties from this URL http://quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigJDBCJobStoreClustering will only work if I rename all the packages to follow the same pattern. Well, I'd suggest to document this somewhere :-) Another thing is that I've created a very very simple example using two different TomEE+ 1.7.0 using the same code, both pointing to the same DB, like this package test; import java.util.Date; import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.ejb.Lock; import javax.ejb.LockType; import javax.ejb.Schedule; import javax.ejb.ScheduleExpression; import javax.ejb.Singleton; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerConfig; import javax.ejb.TimerService; import org.apache.openejb.core.timer.TimerData; import org.apache.openejb.quartz.JobKey; import org.apache.openejb.quartz.Scheduler; import org.apache.openejb.quartz.SchedulerException; import org.apache.openejb.quartz.Trigger; import org.apache.openejb.quartz.impl.StdSchedulerFactory; import org.apache.openejb.quartz.impl.matchers.GroupMatcher; @Singleton @Lock(LockType.READ) public class MyQuartzService { @Resource private TimerService timerService; private long name = System.currentTimeMillis(); @PostConstruct public void init() { System.out.println(name+" initialized"); ScheduleExpression exp = new ScheduleExpression(); exp.minute("0,5,10,15,20,25,30,35,40,45,50,55"); exp.hour("*"); exp.second(30); //does not make any difference TimerConfig config = new TimerConfig(); config.setInfo("hello "+name); Timer created = timerService.createCalendarTimer(exp,config); System.out.println("created "+created.getInfo()); System.out.println("handle "+created.getHandle().toString()); } @Timeout public void executeTimer(Timer timer) throws Exception { System.out.println(name+" executeTimer ("+getInfo(timer)+") "+new Date()); } /** * <br>17/10/2014 * * @param timer * @return * @throws SchedulerException */ private String getInfo(Timer timer) throws SchedulerException { Scheduler scheduler = new StdSchedulerFactory().getScheduler("MyClusteredScheduler"); for (String groupName : scheduler.getJobGroupNames()) { for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) { for (Trigger trigger : (List<Trigger>) scheduler.getTriggersOfJob(jobKey)) { TimerData timerData = (TimerData)trigger.getJobDataMap().get("TIMER_DATA"); Object s = timerData.getInfo(); if (s instanceof String){ String timerInfo = ((String) s); return timerInfo; } }//for trigger }//for jobkey }//for groupname return null; } @Schedule(hour="*", minute="*") public void executeEveryMinute() { System.out.println(name+" executeEveryMinute "+new Date()); } //Fail to parse schedule expression javax.ejb.ScheduleExpression@78aded17 // @Schedule(hour="*", minute="5/*") @Schedule(hour="*", minute="0,5,10,15,20,25,30,35,40,45,50,55") public void executeEvery5Minutes() { System.out.println(name+" executeEvery5Minutes "+new Date()); } } and #============================================================================ # Configure Main Scheduler Properties #============================================================================ org.apache.openejb.quartz.scheduler.instanceName = MyClusteredScheduler org.apache.openejb.quartz.scheduler.instanceId = AUTO #============================================================================ # Configure ThreadPool #============================================================================ org.apache.openejb.quartz.threadPool.class = org.apache.openejb.quartz.simpl.SimpleThreadPool org.apache.openejb.quartz.threadPool.threadCount = 25 org.apache.openejb.quartz.threadPool.threadPriority = 5 #============================================================================ # Configure JobStore #============================================================================ org.apache.openejb.quartz.jobStore.misfireThreshold = 60000 org.apache.openejb.quartz.jobStore.class = org.apache.openejb.quartz.impl.jdbcjobstore.JobStoreTX org.apache.openejb.quartz.jobStore.driverDelegateClass = org.apache.openejb.quartz.impl.jdbcjobstore.oracle.OracleDelegate org.apache.openejb.quartz.jobStore.useProperties = false org.apache.openejb.quartz.jobStore.dataSource = myDS org.apache.openejb.quartz.jobStore.tablePrefix = QRTZ_ org.apache.openejb.quartz.jobStore.isClustered = true org.apache.openejb.quartz.jobStore.clusterCheckinInterval = 20000 #============================================================================ # Configure Datasources #============================================================================ org.apache.openejb.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver org.apache.openejb.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@localhost :1521:XE org.apache.openejb.quartz.dataSource.myDS.user = xxxxxx org.apache.openejb.quartz.dataSource.myDS.password = xxxxxx org.apache.openejb.quartz.dataSource.myDS.maxConnections = 5 org.apache.openejb.quartz.dataSource.myDS.validationQuery=select 0 from dual well, here's what it seems to be happening logs from server 1 Informações: Server startup in 3246 ms 1413583920154 initialized *created hello 1413583920154* handle org.apache.openejb.core.timer.TimerHandleImpl@5a483ce 1413583920154 executeEveryMinute Fri Oct 17 19:12:00 BRT 2014 1413583920154 executeEvery5Minutes Fri Oct 17 19:15:00 BRT 2014 *1413583920154 executeTimer (hello 1413583260198) Fri Oct 17 19:15:30 BRT 2014* 1413583920154 executeEveryMinute Fri Oct 17 19:16:00 BRT 2014 1413583920154 executeEveryMinute Fri Oct 17 19:17:00 BRT 2014 1413583920154 executeEveryMinute Fri Oct 17 19:19:00 BRT 2014 1413583920154 executeEveryMinute Fri Oct 17 19:20:00 BRT 2014 1413583920154 executeTimer (hello 1413583260198) Fri Oct 17 19:20:30 BRT 2014 logs from server 2 Informações: Server startup in 3243 ms 1413583980207 initialized *created hello 1413583980207* handle org.apache.openejb.core.timer.TimerHandleImpl@77c24f14 1413583980207 executeEveryMinute Fri Oct 17 19:13:00 BRT 2014 1413583980207 executeEveryMinute Fri Oct 17 19:14:00 BRT 2014 1413583980207 executeEveryMinute Fri Oct 17 19:15:00 BRT 2014 1413583980207 executeEveryMinute Fri Oct 17 19:18:00 BRT 2014 1413583980207 executeEvery5Minutes Fri Oct 17 19:20:00 BRT 2014 "*hello 1413583260198*" was created in a previous attempt, so my feeling is that, somehow, even creating a new timer on every server restart, tomEE (or Quartz) is assuming that the calendar timer is already created (checking by cron expression maybe?). In fact, in the DB, there are only 3 triggers everytime. Another thing I've noticed is that the code seems not to accept the cron-like expression, for example @Schedule(hour="*", minute="0,5,10,15,20,25,30,35,40,45,50,55") public void executeEvery5Minutes() { System.out.println(name+" executeEvery5Minutes "+new Date()); } works while @Schedule(hour="*", minute="5/*") public void executeEvery5Minutes() { System.out.println(name+" executeEvery5Minutes "+new Date()); } does not the cron-like is described at http://docs.oracle.com/javaee/6/api/javax/ejb/ScheduleExpression.html Please tell me if this is the expected behavior, because maybe I am not getting the spec, but I thought it would be possible to create different triggers for different jobs even if they had the same cron expression. TIA [] Leo On Fri, Oct 17, 2014 at 4:48 PM, Leonardo K. Shikida <[email protected]> wrote: > Just a note > > Romain had it in a blog already since 2012... next time I'll do some > research first > > > http://rmannibucau.wordpress.com/2012/08/22/tomee-quartz-configuration-for-scheduled-methods/ > > Tested here using 1.6.0.2 and it works like a charm, for both ways (static > and dynamic timers) > > Curiously, Quartz works as a cluster even if tomee is not clustered (very > smart). > > Also noticed that this configuration needs some extra jars (probably > indicated somewhere in the quartz documentation, I guess, such as c3p0) and > my quartz DB script had a little bug (probably outdated - > https://code.google.com/p/myschedule/issues/detail?id=131) > > Other than that, it just seems to work very well. > > Thanks again, pals. > > Leo > > > > > [] > > Leo > > On Fri, Oct 17, 2014 at 10:41 AM, Leonardo K. Shikida <[email protected]> > wrote: > >> Thanks Andy and Romain. That's exactly what I was looking for. >> >> [] >> >> Leo >> >> On Thu, Oct 16, 2014 at 11:37 AM, Andy Gumbrecht < >> [email protected]> wrote: >> >>> Hi Leonardo, >>> >>> Never feel like a question is dumb if you're searching for an answer. >>> That's why we are here. >>> >>> You will find information on clustering Quartz using a JDBC JobStore >>> here: http://quartz-scheduler.org/generated/2.2.1/html/qs-all/# >>> page/Quartz_Scheduler_Documentation_Set/re-cls_ >>> cluster_configuration.html# >>> >>> Just make sure those properties are consistent across your TomEE cluster >>> and you'll be fine. >>> >>> The @Schedule is more tricky as you will be responsible for obtaining a >>> cluster wide lock from that method. >>> The easiest way would be to configure a DataSource to a central database >>> that is accessible by all the TomEE instances in the cluster - Use a simple >>> table with a BIT type and a DATETIME >>> Whichever '@Schedule' method gets the lock can then run the operation >>> (and unlock afterwards, so use a try/finally block) - The date can be used >>> to check for a lock timeout if a method fails to unlock for whatever reason >>> (a crash for example). >>> >>> Andy. >>> >>> >>> On 16/10/2014 12:27, Leonardo K. Shikida wrote: >>> >>>> Hi >>>> >>>> this doubt may sound dumb, but if I have an EJB with a scheduled task >>>> like >>>> >>>> @Schedule(dayOfWeek = "*") >>>> public void runMeDaily() {...} >>>> >>>> and if I am in a clustered environment, is there any way to make this >>>> job >>>> run in only one of the instances? (only once) >>>> >>>> of course, I can set a flag somewhere and check it before the execution >>>> of >>>> such task, so only the first cluster instance would run it, but I am >>>> curious if it's possible using some configuration magic. >>>> >>>> another doubt is: if I have 2 clustered tomee instances, how do I make >>>> both >>>> point to the same scheduler? By scheduler I mean something like >>>> >>>> Scheduler scheduler = new StdSchedulerFactory(). >>>> getScheduler("myScheduler"); >>>> >>>> My feeling is that my cluster will need a centralized quartz scheduler >>>> service somehow, so if there's some way to do that using tomee, it >>>> would be >>>> useful for me. >>>> >>>> TIA >>>> >>>> Leo >>>> >>>> >>> >>> -- >>> Andy Gumbrecht >>> https://twitter.com/AndyGeeDe >>> http://www.tomitribe.com >>> >>> >> >
