Имейте расписание задач EJB с "синтаксисом crontab" - PullRequest
7 голосов
/ 09 сентября 2011

Я пытаюсь выяснить, какие возможности у меня есть, чтобы решить следующую проблему.

a) Я хочу иметь таблицу базы данных, которая использует «синтаксис crontab» для планирования задач, структура будет выглядеть примерно так:this:

    |-Id-|---Crontab Syntax---|---------Task----------|
    | 1  | 30 *  *  *  *    * | MyClass.TaskA(args[]) |
    | 2  | 0  1  *  *  1-5  * | MyClass.TaskB(args[]) |
    |    |                    |                       |

Таблица выше будет изменена в любое время внешним приложением.Добавленные или удаленные задачи должны немедленно повлиять на планировщик.

b) Сам планировщик должен находиться на сервере приложений Java.Он должен постоянно синхронизироваться с активными запланированными задачами в таблице базы данных.Всякий раз, когда происходит событие расписания, оно должно запускать / вызывать EJB со значением в качестве значения параметра «Задача».

Я не ищу ответа на вышеуказанную проблему.Но скорее некоторый вклад в то, какие структуры могут использоваться для разбора crontab и каким образом должен быть развернут EJB, представляющий планировщик.

Заранее спасибо.

Ответы [ 3 ]

27 голосов
/ 09 сентября 2011

См. EJB 3.1 @Schedule API. API, который мы выбрали для спецификации, немного ближе к синтаксису Quartz, чем cron - небольшие различия между ними.

Вот пример аннотации:

package org.superbiz.corn;

import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Schedule;
import javax.ejb.Schedules;
import javax.ejb.Singleton;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * This is where we schedule all of Farmer Brown's corn jobs
 */
@Singleton
@Lock(LockType.READ) // allows timers to execute in parallel
public class FarmerBrown {

    private final AtomicInteger checks = new AtomicInteger();

    @Schedules({
            @Schedule(month = "5", dayOfMonth = "20-Last", minute = "0", hour = "8"),
            @Schedule(month = "6", dayOfMonth = "1-10", minute = "0", hour = "8")
    })
    private void plantTheCorn() {
        // Dig out the planter!!!
    }

    @Schedules({
            @Schedule(month = "9", dayOfMonth = "20-Last", minute = "0", hour = "8"),
            @Schedule(month = "10", dayOfMonth = "1-10", minute = "0", hour = "8")
    })
    private void harvestTheCorn() {
        // Dig out the combine!!!
    }

    @Schedule(second = "*", minute = "*", hour = "*")
    private void checkOnTheDaughters() {
        checks.incrementAndGet();
    }

    public int getChecks() {
        return checks.get();
    }
}

Полный источник для этого здесь

Вы можете сделать то же самое программно через класс ScheduleExpression , который является просто конструктивной версией вышеупомянутой аннотации. Вот как будет выглядеть приведенный выше пример, если расписание составлено в коде:

package org.superbiz.corn;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.ScheduleExpression;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * This is where we schedule all of Farmer Brown's corn jobs
 *
 * @version $Revision$ $Date$
 */
@Singleton
@Lock(LockType.READ) // allows timers to execute in parallel
@Startup
public class FarmerBrown {

    private final AtomicInteger checks = new AtomicInteger();

    @Resource
    private TimerService timerService;

    @PostConstruct
    private void construct() {
        final TimerConfig plantTheCorn = new TimerConfig("plantTheCorn", false);
        timerService.createCalendarTimer(new ScheduleExpression().month(5).dayOfMonth("20-Last").minute(0).hour(8), plantTheCorn);
        timerService.createCalendarTimer(new ScheduleExpression().month(6).dayOfMonth("1-10").minute(0).hour(8), plantTheCorn);

        final TimerConfig harvestTheCorn = new TimerConfig("harvestTheCorn", false);
        timerService.createCalendarTimer(new ScheduleExpression().month(9).dayOfMonth("20-Last").minute(0).hour(8), harvestTheCorn);
        timerService.createCalendarTimer(new ScheduleExpression().month(10).dayOfMonth("1-10").minute(0).hour(8), harvestTheCorn);

        final TimerConfig checkOnTheDaughters = new TimerConfig("checkOnTheDaughters", false);
        timerService.createCalendarTimer(new ScheduleExpression().second("*").minute("*").hour("*"), checkOnTheDaughters);
    }

    @Timeout
    public void timeout(Timer timer) {
        if ("plantTheCorn".equals(timer.getInfo())) {
            plantTheCorn();
        } else if ("harvestTheCorn".equals(timer.getInfo())) {
            harvestTheCorn();
        } else if ("checkOnTheDaughters".equals(timer.getInfo())) {
            checkOnTheDaughters();
        }
    }

    private void plantTheCorn() {
        // Dig out the planter!!!
    }

    private void harvestTheCorn() {
        // Dig out the combine!!!
    }

    private void checkOnTheDaughters() {
        checks.incrementAndGet();
    }

    public int getChecks() {
        return checks.get();
    }
}

Источник для этого примера здесь

Примечание: оба примера запускаются в простой IDE и имеют тестовые наборы, в которых используется API Embeddable EJBContainer , также новый в EJB 3.1.

@ Schedule против ScheduleExpression

  • @ Расписание
    • Статически настроенный
    • Возможны многие методы расписания
    • Невозможно передать аргументы
    • Не может быть отменено

Все вышеперечисленное делается в дескрипторе развертывания и поэтому ограничивается только теми вещами, которые могут быть настроены заранее. В более динамичной версии используется следующая подпись TimerService:

TimerService.createCalendarTimer (javax.ejb.ScheduleExpression, javax.ejb.TimerConfig)

  • ScheduleExpression
    • Динамически создается
    • Ровно один @Timeout поддерживает все ScheduleExpression
    • Метод тайм-аута должен принимать javax.ejb.Timer в качестве параметра
    • Аргументы могут быть переданы
    • Может быть отменено вызывающим абонентом или методом @Timeout

Также обратите внимание, что существует аннотация перехватчика @AroundTimeout, которая функционирует идентично @AroundInvoke и позволяет перехватчикам участвовать в функциях таймера компонента.

0 голосов
/ 09 сентября 2011

EJB имеет свои собственные встроенные таймеры , но вам придется написать шаблонный код для преобразования разбора cron. Разбор самих команд cron должен быть тривиальным.

Если вы не боитесь выходить за пределы EJB, Quartz - отличный выбор для лексикора.

0 голосов
/ 09 сентября 2011

Взгляните на Кварц . Если вы используете Spring, там очень хорошая поддержка. Аккуратная, надежная, хорошо работающая вещь.

...