我们有一个.NET项目,它检查远程计算机上是否存在一个文件。我们需要对一个部门内的多台远程计算机(数千台)执行此操作,每台计算机每天都在预定义的时间执行。执行时间是在数据库中指定的,它经常变化,每台远程计算机的执行时间都是不同的(有些可能是相同的)。为了实现这一点,我们计划使用Quartz调度器。由于我们是石英的新手,我们想知道如何实现这一点。在高层,我们需要这些-
需要哪种类型的项目/组成部分来实现上述目标?我们已经有一个检查远程计算机的.NET类库项目。我们如何与石英整合?
非常感谢granadaCoder
让我知道你对这种方法的看法。
此外,我们有多个部门(总共4个),所以我想写4个控制台应用程序--每个部门一个。并且使用任务调度器来调度所有的应用程序(同时,不同的定时可能没有帮助,因为每个部门可能有工作触发时间跨越一整天)。
另外,我还想知道是否可以在quartz.config文件中指定4个具有相同触发时间的作业?(不确定这将如何工作,它是否会创建4个特定于部门的调度程序实例,并且我们可以将部门的作业排队到每个调度程序实例?)
>
编写一个在.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使用下面的代码对作业进行调度。 详细信息存储在表中--、&