棘手的 Quartz.NET 场景
本文关键字:NET 场景 Quartz | 更新日期: 2023-09-27 18:35:53
好的,这里有一点背景。我有一个大型Web应用程序(MVC3),它可以做各种不重要的事情。我需要此 Web 应用程序能够在 Oracle 数据库中安排临时 Quartz.NET 作业。然后,我希望稍后通过Windows服务执行作业。理想情况下,我想安排它们以偶数间隔运行,但可以选择通过 Web 应用程序添加作业。
基本上,所需的体系结构是此体系结构的某种变体:
Web 应用程序<--> Quartz.NET <-->数据库<--> Quartz.NET <--> Windows Service
到目前为止,我编码的内容:
- 一个Windows服务,它(目前)调度并运行作业。从长远来看,这显然不会是这种情况,但我想知道我是否可以保留它并对其进行修改,使其基本上代表上图中的"Quartz.NET"。
- 网络应用程序(我想细节在这里不是很重要)
- 工作(实际上只是另一个Windows服务)
还有几个重要的注意事项:
- 它必须从Windows服务运行,并且必须通过Web应用程序进行计划(以减少IIS上的负载)
- 上面的架构可以稍微重新排列一下,假设上面的项目符号仍然适用。
现在,有几个问题:
- 这可能吗?
- 假设 (1) 通过,你们认为最好的架构是什么?请参阅我编码的第一个项目符号。
- 有人可以给我一些 Quartz 方法来帮助我在计划作业后查询数据库以执行作业吗?
一旦符合条件,将立即对此问题进行赏金。如果在此之前问题得到满意的回答,我仍然会把赏金奖励给答案的发帖人。所以,无论如何,如果你在这里给出一个好的答案,你会得到赏金。
我会尝试按照你的顺序回答你的问题。
-
是的,可以这样做。这实际上是与 Quartz.Net 合作的一种常见方式。实际上,您还可以编写一个 ASP.Net MVC 应用程序来管理 Quartz.Net 调度程序。
-
建筑。理想情况下,在高级别上,MVC 应用程序将使用 Quartz.Net API 与作为 Windows 服务安装在某处的 Quartz.Net 服务器进行通信。Quartz.Net 使用远程处理进行远程通信,因此使用远程处理的任何限制都适用(例如 Silverlight 等不支持它)。Quartz.Net 提供了一种将其安装为开箱即用的Windows服务的方法,因此除了将服务本身配置为使用(在您的情况下)AdoJobStore以及启用远程处理之外,这里实际上没有太多工作要做。关于如何正确安装服务需要注意一些注意事项,因此,如果您还没有这样做,请查看这篇文章。
在内部,在 MVC 应用程序中,您需要获取对调度程序的引用,并将其存储为单一实例。然后在代码中,您将计划作业,并通过此唯一实例获取有关计划程序的信息。你可以使用这样的东西:
public class QuartzScheduler
{
public QuartzScheduler(string server, int port, string scheduler)
{
Address = string.Format("tcp://{0}:{1}/{2}", server, port, scheduler);
_schedulerFactory = new StdSchedulerFactory(getProperties(Address));
try
{
_scheduler = _schedulerFactory.GetScheduler();
}
catch (SchedulerException)
{
MessageBox.Show("Unable to connect to the specified server", "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
public string Address { get; private set; }
private NameValueCollection getProperties(string address)
{
NameValueCollection properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "RemoteClient";
properties["quartz.scheduler.proxy"] = "true";
properties["quartz.threadPool.threadCount"] = "0";
properties["quartz.scheduler.proxy.address"] = address;
return properties;
}
public IScheduler GetScheduler()
{
return _scheduler;
}
}
此代码设置您的 Quart.Net 客户端。然后要访问远程调度程序,只需调用
GetScheduler()
查询下面是一些从调度程序获取所有作业的示例代码:
public DataTable GetJobs() { DataTable table = new DataTable(); table.Columns.Add("GroupName"); table.Columns.Add("JobName"); table.Columns.Add("JobDescription"); table.Columns.Add("TriggerName"); table.Columns.Add("TriggerGroupName"); table.Columns.Add("TriggerType"); table.Columns.Add("TriggerState"); table.Columns.Add("NextFireTime"); table.Columns.Add("PreviousFireTime"); var jobGroups = GetScheduler().GetJobGroupNames(); foreach (string group in jobGroups) { var groupMatcher = GroupMatcher<JobKey>.GroupContains(group); var jobKeys = GetScheduler().GetJobKeys(groupMatcher); foreach (var jobKey in jobKeys) { var detail = GetScheduler().GetJobDetail(jobKey); var triggers = GetScheduler().GetTriggersOfJob(jobKey); foreach (ITrigger trigger in triggers) { DataRow row = table.NewRow(); row["GroupName"] = group; row["JobName"] = jobKey.Name; row["JobDescription"] = detail.Description; row["TriggerName"] = trigger.Key.Name; row["TriggerGroupName"] = trigger.Key.Group; row["TriggerType"] = trigger.GetType().Name; row["TriggerState"] = GetScheduler().GetTriggerState(trigger.Key); DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc(); if (nextFireTime.HasValue) { row["NextFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(nextFireTime.Value.DateTime); } DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc(); if (previousFireTime.HasValue) { row["PreviousFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(previousFireTime.Value.DateTime); } table.Rows.Add(row); } } } return table; }
您可以在 Github 上查看此代码