使用属性/XML文件在Quartz中将脚本动态添加为作业

9
场景:我想创建一个调度程序应用,它应该按照定义的时间表运行shell脚本。为了简化,我希望用户将脚本名称和执行时间添加到一些外部文件(属性/xml)中,这些文件将被我的应用程序使用。现在,我计划在Linux服务器上将此应用程序作为后台进程运行。未来可能会将其制作成Web应用程序。

我到目前为止尝试过的:

  1. 我遇到了xmlschedulingdataprocessorplugin,但它要求用户编写作业作为Java代码,然后将其添加到XML文件中。
  2. 我找到了一些用于调度的示例,但目前不起作用。

请建议一些有用的Quartz API,可以帮助我实现这个目的。

更新:

public class CronTriggerExample {
public static void main(String[] args) throws Exception {

  String[] a = {"script1.sh:0/10 * * * * ?", "script2.sh:0/35 * * * * ?"};

    for (String config : a) {

        String[] attr = config.split(":");
        System.out.println("Iterating for : "+attr[0]);

        JobKey jobKey = new JobKey(attr[0], attr[0]);

        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity(attr[0], attr[0])
                .withSchedule(CronScheduleBuilder.cronSchedule(attr[1]))
                .build();

        Scheduler scheduler = new StdSchedulerFactory().getScheduler();

        scheduler.getContext().put("val", config);
        JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity(jobKey).build();

        scheduler.start();
        scheduler.scheduleJob(job, trigger);
        System.out.println("=======================");
      }
  }
}

我的HelloJob类:

public class HelloJob implements Job {

public void execute(JobExecutionContext context) throws JobExecutionException {
    String objectFromContext = null;
    Date date = new Date();
    try {
        SchedulerContext schedulerContext = context.getScheduler().getContext();
        objectFromContext = (String) schedulerContext.get("val");

    } catch (SchedulerException ex) {
        ex.printStackTrace();
    }

    System.out.println("Triggered "+objectFromContext+" at: "+date);

  }
}

输出:

Iterating for : script1.sh
log4j:WARN No appenders could be found for logger    (org.quartz.impl.StdSchedulerFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
=======================
Iterating for : script2.sh
=======================
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:21:50 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:00 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:00 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:10 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:20 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:30 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:35 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:40 IST 2016

我错过了什么吗?我尝试为每个迭代创建新的作业,并将脚本名称分配为 JobExecutionContext


你是否考虑过使用Cron和/或Java应用程序来解析XML以更新crontab? - CptBartender
3个回答

2
我会采取以下方法:

我会采用以下方法:

  • You create a class JobShellRunner which will implement Job interface from quartz :

    public class JobShellRunner implements Job {
    
    @Override
    public void execute(JobExecutionContext context)
        throws JobExecutionException {
        // here you take need information about the shell script you need to run, from the context and run the shell script 
    }
    

    }

  • read properties files (i suppose here it will be available information about which shell script to run and it's schedule information). For each information needed you will create it's context and it's trigger:

    JobKey jobKey = new JobKey("jobShellRunner", "group1");
    // put in the job key need information about shell script (path, etc)
    JobDetail jobA = JobBuilder.newJob(JobShellRunner.class)
    .withIdentity(jobKey).build();
    
  • Then the trigger (note that on the cron expression you should complete with the one that you read from properties file):

    Trigger trigger = TriggerBuilder .newTrigger() .withIdentity("dummyTriggerName1", "group1") .withSchedule( CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) .build();

  • Then schedule the job

    scheduler.scheduleJob(jobA, trigger);


我怀疑这不是解决方案。对于三个具有不同触发器的脚本,我必须创建三个不同的类,然后将它们传递给JobBuilder.newJob,然后相应地附加触发器。 - Shashank Vivek
你在外部文件中有脚本名称,将其作为键放入jobKey中,然后使用JobExecutionContext访问它。这样,您就不必创建3个不同的类。您可以使用JobKey和JobExecutionContext添加一些通用上下文。触发器是独立的,在读取文件的块中构造触发器。 - dumitru

2

我想在运行时添加新的作业,这是简单的执行部分。 - Shashank Vivek

1
你可以按照以下方式进行操作:
首先需要像这样进行:
  1. create your java application which has one scheduled-job which will read at some time interval one propery/xml file which will provide an information for which shell_file needs to execute and at what time.
  2. While your program's scheduled-job read that property/xml file and getting information as following,

     2.1. Shell-Script-File-Name
     2.2. Timing at what time that script needs to be execute.
    
  3. This information which is read by above(step-2), with help of it, this job will create newer independent-job which is fully responsible for execute shell script at particular time.(that time will be your job-time which is read from your propery/xml file). also take care of it to it should be one time only(as per your requirement).

  4. this above step repeatedly does untill whole information read by this job and every time will generate one newer job.

  5. in case after some time user edit/updated/added new line into property/xml file this java program's scheduled job will read only that newer changes and accordingly does as like above explained.

为了更好地理解,您可以看下面的图片:

enter image description here

为了进行调度,您可以设置 spring-quartz API 来进行 schedule job

在这里,我将给您一点 伪代码

public class JobA implements Job {

    @Override
    public void execute(JobExecutionContext context)
            throws JobExecutionException {

        // continues read property/xml file untill while file not read
        // based upon above read info. generate new job(one time only) at runtime which has capability to execute shell script
// shell script can be execute by java program by this ,
//  Runtime.getRuntime().exec("sh /full-path/shell_script_name.sh"); 

    }

}
............
public class CronTriggerExample {
    public static void main( String[] args ) throws Exception
    {

        JobKey jobKeyA = new JobKey("jobA", "group1");
        JobDetail jobA = JobBuilder.newJob(JobA.class)
                .withIdentity(jobKeyA).build();

        Trigger trigger1 = TriggerBuilder
                .newTrigger()
                .withIdentity("dummyTriggerName1", "group1")
                .withSchedule(
                        CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) // you can set here your comfortable job time...
                .build();

        Scheduler scheduler = new StdSchedulerFactory().getScheduler();

        scheduler.start();
        scheduler.scheduleJob(jobA, trigger1);
    }
}

所以,这是我在这里提出并代表的想法,根据您的要求最为合适。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接