tomee-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Leonardo K. Shikida" <shik...@gmail.com>
Subject Re: Cluster + @Schedule
Date Fri, 17 Oct 2014 22:35:42 GMT
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 <shikida@gmail.com>
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 <shikida@gmail.com>
> 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 <
>> agumbrecht@tomitribe.com> 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
>>>
>>>
>>
>

Mime
  • Unnamed multipart/related (inline, None, 0 bytes)
View raw message