首页 文章

如何在Grails中配置Quartz触发器以允许不同的测试和 生产环境 计划

提问于
浏览
3

我正在尝试在Grails 2.2.4中采用Quartz插件(:quartz:1.0.1)并试图弄清楚如何允许开发和测试使用与 生产环境 中所需的不同的计划,而无需更改代码部署到每个 .

Here is my experience.

我正在使用JDBC JobStore和Quartz Monitor插件(:quartz-monitor:1.0) . 所以我的工作定义如下:

class TestJob {
    static triggers = {
        cron name: 'testTrigger', startDelay: 1000, cronExpression: '0 0/1 * * * ?'
    }
    ...
}

当我运行Grails应用程序时,会为作业设置触发器,存储在数据库中,然后开始执行 . 如果我进入并通过Quartz Monitor对cron表达式进行有意更改,则会反映在数据库和执行计划中 .

如果我现在重新启动应用程序,则触发器将更改回作业中定义的内容 . 因此,使用这种方法,我几乎坚持使用触发器块中的任何内容 . 如果我完全从代码中删除触发器块,那么数据库定义将保持不变并控制计划,这似乎是一种改进 .

所以我认为在Job中没有定义任何触发器是有道理的,但是这让我试图弄清楚如何首先加载触发器并且不会覆盖有意的更改 . 似乎在配置中添加一个块(可能在外部配置文件中)来定义触发器是有意义的 . 据我所知,我需要写一些东西来解析它在启动时(在BootStrap?中)并通过Quartz API应用它 .

在我的所有文档阅读和谷歌搜索中都缺少这样的东西吗?或许我可能会以更为根本的方式做错事 .

Update with some implementation details

汉斯给了我一些关于什么应该适用于我的情况的想法 .

我最终关闭了JDBC作业存储,因为我认为配置应该是触发的权限 . 我将作业/触发器信息放入外观配置文件中,如下所示 .

quartzJobs: [
    'TestJob': [
        cronTriggers: [
            cronExpression: '0 0 7 ? * 2-6'
        ]
    ]
]

然后我在BootStrap中调用了一些看起来像这样的代码 .

def jobs = grailsApplication.config.quartzJobs
if (jobs) {
    jobs.each { job, details ->
        List triggers = (details?.cronTriggers instanceof Map) ? [details.cronTriggers]: details.cronTriggers
        if (triggers) {
            def j = grailsApplication.mainContext.getBean(job)
            triggers.each { trigger ->
                String cronExpression = trigger.cronExpression ?: '1 1 1 1 1 ? 2099'
                j.schedule(cronExpression)
            }
        }
    }
}

3 回答

  • 1

    您可以将配置放在 Config.groovy 中,也可以放在从 grails.config.locations 读取的属性文件中 .

    然后在你 BootStrap.groovy 你可以这样做:

    TestJob.schedule(grailsApplication.config.cronExpression)
    

    在此 cronExpression 是您在属性文件中选择的属性的名称 .

    有关可用的不同 Job.schedule() 方法,请参阅http://grails-plugins.github.io/grails-quartz/guide/triggers.html .

  • 2

    您可以执行以下操作以根据当前环境更改触发器:

    static triggers = {
        if (Environment.current == Environment.TEST) {
            simple repeatInterval: 5000l
        }
        else {
            simple repeatInterval: 1000l
        }
    }
    

    Update

    汉斯解决方案可能更容易一些,但是如果它已经存在,那么另一个不会重新创建触发器 . :)

    我重命名了 triggers 块,以便插件找不到任何触发器 .

    package stackoverflow
    
    class MyJob {
        static defaultTriggers = {
            cron name: 'testTrigger', startDelay: 1000, cronExpression: '0 0/1 * * * ?'
        }
    ....
    }
    

    然后我重用 QuartzGrailsPlugin.groovy 中的代码从 defaultTriggers 闭包创建触发器,并在它尚不存在时安排它 .

    通过查看 QuartzGrailsPlugin.groovy 中的 doWithApplicationContext ,扩展代码以循环遍历所有作业应该不会太困难 .

    虽然有点吵 . 我认为最好将其隐藏在服务中并从 Bootstrap 调用它而不是内联 .

    BootStrap.groovy中

    import grails.plugins.quartz.CustomTriggerFactoryBean
    import grails.plugins.quartz.GrailsJobClassConstants
    import grails.plugins.quartz.config.TriggersConfigBuilder
    import org.quartz.JobKey
    import org.quartz.Trigger
    import stackoverflow.MyJob
    
    class BootStrap {
        def quartzScheduler
    
        def init = { servletContext ->
    
            def builder = new TriggersConfigBuilder(MyJob.canonicalName)
            Map triggers = builder.build MyJob.defaultTriggers
    
            triggers.each { name, Expando descriptor ->
                Trigger trigger = createTrigger (descriptor, MyJob.canonicalName)
    
                if (! quartzScheduler.checkExists(trigger.getKey ())) {
                    quartzScheduler.scheduleJob (trigger)
                }
            }
        }
    
        Trigger createTrigger (Expando descriptor, String jobName) {
            CustomTriggerFactoryBean factory = new CustomTriggerFactoryBean()
            factory.triggerClass = descriptor.triggerClass
            factory.triggerAttributes = descriptor.triggerAttributes
            factory.jobDetail = quartzScheduler.getJobDetail (new JobKey (jobName, GrailsJobClassConstants.DEFAULT_GROUP))
            factory.afterPropertiesSet()
            factory.object
        }
    }
    
  • 3

    它可能不是你的方法.1327304_方法 . 此条件可用于基于当前Grails环境以及单独定义的cron表达式跳过执行 . 作为一个非常简单的例子:

    import grails.util.Environment
    import org.quartz.CronExpression
    
    class TestJob {
        CronExpression testExp = new CronExpression("0 0/5 * * * ?")  // could be moved to config...
        // ...
        def execute() {
           // in non-prod environments, return immediately unless the current date & time matches our "test" cron expression
           if (Environment.current != Environment.PRODUCTION && !testExp.isSatisfiedBy(new Date()) { return }
    
           // ...
    
        }
    }
    

相关问题