当前位置: 首页 > 知识库问答 >
问题:

使用Quartz进行调度

廖琪
2023-03-14

我们有一个.NET项目,它检查远程计算机上是否存在一个文件。我们需要对一个部门内的多台远程计算机(数千台)执行此操作,每台计算机每天都在预定义的时间执行。执行时间是在数据库中指定的,它经常变化,每台远程计算机的执行时间都是不同的(有些可能是相同的)。为了实现这一点,我们计划使用Quartz调度器。由于我们是石英的新手,我们想知道如何实现这一点。在高层,我们需要这些-

  1. 调度程序应该在每天的特定时间启动-石英会这样做吗?
  2. 一旦启动,它应该从数据库获取每台远程计算机的执行时间
  3. 准备包含所有远程计算机及其执行时间列表的xml
  4. 计划每个远程计算机的执行
  5. 在每个远程计算机的排定时间执行.NET项目

需要哪种类型的项目/组成部分来实现上述目标?我们已经有一个检查远程计算机的.NET类库项目。我们如何与石英整合?

非常感谢granadaCoder

让我知道你对这种方法的看法。

此外,我们有多个部门(总共4个),所以我想写4个控制台应用程序--每个部门一个。并且使用任务调度器来调度所有的应用程序(同时,不同的定时可能没有帮助,因为每个部门可能有工作触发时间跨越一整天)。

另外,我还想知道是否可以在quartz.config文件中指定4个具有相同触发时间的作业?(不确定这将如何工作,它是否会创建4个特定于部门的调度程序实例,并且我们可以将部门的作业排队到每个调度程序实例?)

共有1个答案

公西宏毅
2023-03-14

>

  • 编写一个在.xml中定义的作业,该作业是执行作业清理和(重新)调度的作业。(下面代码中的“ScheduleOtherJobsJob”)

    ScheduleOtherJobsJob将清除所有旧条目。它读取一些数据存储并计算出它必须执行的新作业列表。它将把这些作业添加到排定程序中。

    我写了一个基本的例子。我没有幻想什么时候运行基于确切日期的逻辑......................................................

    我显示了ScheduleOtherJobsJob的.xml。您可以将其添加到AdoStore或其他任何地方。xml只是更简单的举个例子。

    请记住,您需要一个进程来保持调度程序的“活动”。也就是,您不能向IScheduler添加新的作业,然后终止宿主进程。在console.app中,您可以编写一个“console.readline()”...这样程序就不会停止运行。

    重点是......一项工作来安排其他工作。根据某个筛选器(此处为GROUP_NAME)清除旧作业。根据某些数据存储重新添加作业......并确保主机进程保持运行,以便所有新调度的作业都将运行。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    using Quartz;
    using Quartz.Impl.Matchers;
    
    namespace MyNamespace
    {
    
    
        public class ScheduleOtherJobsJob : IJob
        {
    
            private const string GROUP_NAME = "MySpecialGroupName";
    
            /// <summary> 
            /// Called by the <see cref="IScheduler" /> when a
            /// <see cref="ITrigger" /> fires that is associated with
            /// the <see cref="IJob" />.
            /// </summary>
            public virtual void Execute(IJobExecutionContext context)
            {
    
                JobKey key = context.JobDetail.Key;
    
                JobDataMap jbDataMap = context.JobDetail.JobDataMap;
    
        //            string jobSays = jbDataMap.GetString("KeyOne");
    
                JobDataMap trgDataMap = context.Trigger.JobDataMap;
    
                string triggerParameter001 = trgDataMap.GetString("TriggerFileName");
    
                JobDataMap mergedMap = context.MergedJobDataMap;
    
                string whoWins = mergedMap.GetString("DefinedInJobDetailAndTriggerKey");
    
                string msg = string.Format("HasParametersJob : JobKey='{0}', jobSays='{1}', jobDetailParameter001='{2}', triggerParameter001='{3}', triggerParameter002='{4}' , whoWins='{5}' at '{6}'", key, jobSays, jobDetailParameter001, triggerParameter001, triggerParameter002, whoWins, DateTime.Now.ToLongTimeString());
                Console.WriteLine(msg);
    
                /* */
                context.Scheduler.UnscheduleJobs(GetAllJobTriggerKeys(context.Scheduler));
    
                /* Schedule Your Jobs  */
                List<OtherJobInfo> infos = new OtherJobInfoData().GetOtherJobs();
                foreach (OtherJobInfo info in infos)
                {
                    ScheduleAHasParametersJob(context.Scheduler, info);
                }
    
            }
    
    
            private IList<TriggerKey> GetAllJobTriggerKeys(IScheduler scheduler)
            {
                /* Find all current jobs.....filter here if need be */
    
                IList<TriggerKey> returnItems = new List<TriggerKey>();
    
                IList<string> jobGroups = scheduler.GetJobGroupNames();
                //IList<string> triggerGroups = scheduler.GetTriggerGroupNames();
    
                IList<string> filteredJobGroups = jobGroups.Where(g => g.Equals(GROUP_NAME)).ToList();
    
                foreach (string group in filteredJobGroups)
                {
                    var groupMatcher = GroupMatcher<JobKey>.GroupContains(group);
                    var jobKeys = scheduler.GetJobKeys(groupMatcher);
                    foreach (var jobKey in jobKeys)
                    {
                        var detail = scheduler.GetJobDetail(jobKey);
    
    
                        var triggers = scheduler.GetTriggersOfJob(jobKey);
                        foreach (ITrigger trigger in triggers)
                        {
                            returnItems.Add(trigger.Key);
    
                            Console.WriteLine(group);
                            Console.WriteLine(jobKey.Name);
                            Console.WriteLine(detail.Description);
                            Console.WriteLine(trigger.Key.Name);
                            Console.WriteLine(trigger.Key.Group);
                            Console.WriteLine(trigger.GetType().Name);
                            Console.WriteLine(scheduler.GetTriggerState(trigger.Key));
                            DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc();
                            if (nextFireTime.HasValue)
                            {
                                Console.WriteLine(nextFireTime.Value.LocalDateTime.ToString());
                            }
    
                            DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc();
                            if (previousFireTime.HasValue)
                            {
                                Console.WriteLine(previousFireTime.Value.LocalDateTime.ToString());
                            }
                        }
                    }
                }
    
                return returnItems;
            }
    
    
    
            private static void ScheduleAHasParametersJob(IScheduler sched, OtherJobInfo info)
            {
    
                IJobDetail hasParametersJobDetail = JobBuilder.Create<FileNameDoSomethingJob>()
                    .WithIdentity(info.UniqueIdentifier + "IJobDetailWithIdentity", GROUP_NAME)
                    //.UsingJobData("JobDetailFileName", info.FileName)
                    .Build();
    
    
                ITrigger hasParametersJobTrigger001 = TriggerBuilder.Create()
                  .WithIdentity(info.UniqueIdentifier + "ITriggerWithIdentity", GROUP_NAME)
                    .UsingJobData("TriggerFileName", info.FileName)
                  .StartNow()
                  .WithSimpleSchedule(x => x
                      .WithIntervalInSeconds(info.WithIntervalInSeconds) /* You'll have to do something fancier here with scheduling if you want an exact time */
                      .WithRepeatCount(0))
                  .Build();
    
    
    
                sched.ScheduleJob(hasParametersJobDetail, hasParametersJobTrigger001);
            }
    
        }
    
    
    
    
        public class FileNameDoSomethingJob : IJob
        {
            public virtual void Execute(IJobExecutionContext context)
            {
                JobKey key = context.JobDetail.Key;
    
                JobDataMap jbDataMap = context.JobDetail.JobDataMap;
    
                JobDataMap trgDataMap = context.Trigger.JobDataMap;
    
                string triggerFileNameParameter = trgDataMap.GetString("TriggerFileName");
    
                JobDataMap mergedMap = context.MergedJobDataMap;
    
                string msg = string.Format("HasParametersJob : JobKey='{0}', triggerFileNameParameter='{1}' at '{2}'", key, triggerFileNameParameter, DateTime.Now.ToLongTimeString());
                Console.WriteLine(msg);
            }
        }
    
    
    
    
        public class OtherJobInfoData
        {
    
            public List<OtherJobInfo> GetOtherJobs()
            {
                List<OtherJobInfo> returnItems = new List<OtherJobInfo>();
    
                OtherJobInfo oji1 = new OtherJobInfo() { UniqueIdentifier = "ABC123", WithIntervalInSeconds = 5, FileName = @"C:\file1.xml"};
                OtherJobInfo oji2 = new OtherJobInfo() { UniqueIdentifier = "DEF234", WithIntervalInSeconds = 5, FileName = @"C:\file2.xml" };
                OtherJobInfo oji3 = new OtherJobInfo() { UniqueIdentifier = "GHI345", WithIntervalInSeconds = 5, FileName = @"C:\file3.xml" };
    
                returnItems.Add(oji1);
                returnItems.Add(oji2);
                returnItems.Add(oji3);
    
                return returnItems;
            }
        }
    
        public class OtherJobInfo
        {
            public string UniqueIdentifier { get; set; }
            public int WithIntervalInSeconds { get; set; }
            public string FileName { get; set; }
        }
    
    }
    

    和一些xml来运行ScheduleOtherJobsJob

    <?xml version="1.0" encoding="UTF-8"?>
    
    <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
    
    
        <!-- This value wipes out existing jobs...be very careful with it being "true"  -->
        <processing-directives>
            <overwrite-existing-data>true</overwrite-existing-data>
        </processing-directives>
    
        <schedule>
    
    
    
            <job>
                <name>ScheduleOtherJobsJobName</name>
                <group>ScheduleOtherJobsJobGroupName</group>
                <description>My Description</description>
                <job-type>MyNamespace.ScheduleOtherJobsJob, MyAssembly</job-type>
                <durable>true</durable>
                <recover>false</recover>
                <job-data-map>
                </job-data-map>
            </job>
            <trigger>
    
                <simple>
                    <name>ScheduleOtherJobsJobTriggerName</name>
                    <group>ScheduleOtherJobsJobTriggerGroup</group>
                    <description>My ScheduleOtherJobsJobTriggerName Description</description>
                    <job-name>ScheduleOtherJobsJobName</job-name>
                    <job-group>ScheduleOtherJobsJobGroupName</job-group>
    
    
                    <job-data-map>
                    </job-data-map>
    
                    <!--<start-time>1982-06-28T18:15:00.0Z</start-time>-->
                    <!--<end-time>2020-05-04T18:13:51.0Z</end-time>-->
                    <misfire-instruction>SmartPolicy</misfire-instruction>
                    <!-- repeat indefinitely every 5 seconds -->
                    <repeat-count>-1</repeat-count>
                    <repeat-interval>5000</repeat-interval>
    
    
    
                </simple>
    
            </trigger>
    
        </schedule>
    
    
    
    </job-scheduling-data>
    

    确保您的app.config(或web.config)指向的是quartz-configuration文件。这是我的顶部......注意,它应该作为一个指南.....

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    
    
        <configSections>
            <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    
    
        </configSections>
    
    
    
    
        <quartz configSource="MyQuartzConfiguration.config" />
    

    然后MyQuartzConfiguration.config文件需要一些东西,最重要的是“quartz_jobs_001.xml”(名称并不重要,但该文件包含作业和触发器的信息)。

    <add key="quartz.plugin.jobInitializer.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin" />
    <add key="quartz.scheduler.instanceName" value="DefaultQuartzScheduler" />
    <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
    <add key="quartz.threadPool.threadCount" value="10" />
    <add key="quartz.threadPool.threadPriority" value="2" />
    <add key="quartz.jobStore.misfireThreshold" value="60000" />
    <add key="quartz.jobStore.type" value="Quartz.Simpl.RAMJobStore, Quartz" />
    <add key="quartz.plugin.jobInitializer.fileNames" value="Quartz_Jobs_001.xml" />
    <add key="quartz.plugin.jobInitializer.failOnFileNotFound" value="true" />
    <add key="quartz.plugin.jobInitializer.scanInterval" value="120" />
    

  •  类似资料:
    • 问题内容: 我必须编写一个执行一系列任务的应用程序: 该任务每天0200小时运行一次。 每天0400小时运行一次任务 从0003小时开始,每15分钟运行一次任务 从0005小时开始,每15分钟运行一次任务 使用纯java.util.timer和VS的优缺点是什么?石英呢? 我还有其他选择吗? 问题答案: 石英 附加依赖 当前(2011年末)API发生了变化:1.x即将退出,但Spring和其他可能

    • 我正在利用石英调度,有2个工作。第一个工作是执行大约2分钟的任务,第二个是设置为临时文件的清理操作。因此,我需要设置时间表,以一种方式工作,即在第一个作业被执行/完成执行任务后,我需要在第二个作业的帮助下进行清洁操作。 考虑到Quartz 2.1.x下的示例9-Job Listeners,该示例说明我们可以定义一个名为jobWasExecuted(_,_)的方法;并在第一个作业被执行/或处于运行状

    • 我们如何用Quartz调度器或任何Java/Spring api来实现这一点? 例如,假设任何石英作业启动,并且间隔设置为10分钟,因此在理想情况下,作业将在下一个10分钟间隔内运行。但每次作业运行时,我们都希望从数据库中获取最新的时间间隔并对其进行调度。 10:00作业运行且在数据库中的时间间隔设置为10分钟10:10作业运行且在数据库中的时间间隔设置为20分钟 所以下一次作业应该在10:30运

    • 24.2. 使用OpenSymphony Quartz 调度器 Quartz使用Trigger, Job以及JobDetail等对象来进行各种类型的任务调度。关于Quartz的基本概念,请参阅http://www.opensymphony.com/quartz。为了让基于Spring的应用程序方便使用,Spring提供了一些类来简化uartz的用法。 24.2.1. 使用JobDetailBean

    • 这是我第一次存储作业,并使用crontrigger使用下面的代码对作业进行调度。 详细信息存储在表中--、&