通过 Web 服务公开的 Quartz.NET 调度器






2.92/5 (5投票s)
通过 Web 服务公开 Quartz.NET 调度器
我收到一个业务需求,需要提供一个自助式网站来进行作业调度。由于我使用过 Quartz.Net,它似乎是调度和处理作业的完美后端引擎。我决定通过一些 Web 方法公开 Quartz.Net 的功能,使用 Web 服务来实现,以便在 Excel、SharePoint、Web 或桌面应用程序中进行消费。在这篇博文中,我将向您展示如何通过 Web 服务公开 Quartz.Net。
01 – 架构
- 调度器 Web 服务 (Scheduler.asmx) 托管在 Web 服务器上。
- 我目前有 3 台应用程序服务器,它们将 Quartz.Net 作为 Windows 服务运行。这些应用程序服务器的名称是“Alpha”、“Beta”和“Gamma”。我添加了防火墙例外,允许 Quartz.Net 在 555 端口上监听。
- 标签:有趣!现在你可能会问,标签是什么?标签基本上是我识别我的 quartz 应用程序服务器能够运行哪种类型的计划作业的方式。例如,Alpha 仅配备了用于调度 PowerShell 特定作业的功能,而 Beta 可以调度 VBA 作业,Gamma 可以调度需要 cmd 进程的任何作业。您可以将其扩展到包括 .NET、Python 或只是不同版本的进程。
- XML:您看到的从用户流向 Web 服务器的 XML 是作业描述,即,调度作业 X 的请求,同时指定计划、优先级等。
02 – 业务逻辑
请参阅下面有关您在 Web 服务签名中看到的方法的业务逻辑。
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Linq;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Matchers;
using Rte.Model.Entities;
namespace Scheduler.Business
{
public class Scheduler
{
public readonly IScheduler Instance;
public string Address { get; private set; }
public string JobName { get; set; }
public string JobGroup { get; set; }
public int Priority { get; set; }
public string CronExpression { get; set; }
private readonly ISchedulerFactory _schedulerFactory;
public Scheduler(string server, int port, string scheduler)
{
Address = string.Format("tcp://{0}:{1}/{2}", server, port, scheduler);
_schedulerFactory = new StdSchedulerFactory(GetProperties(Address));
try
{
Instance = _schedulerFactory.GetScheduler();
if (!Instance.IsStarted)
Instance.Start();
}
catch (SchedulerException ex)
{
throw new Exception(string.Format("Failed: {0}", ex.Message));
}
}
private static NameValueCollection GetProperties(string address)
{
var properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "ServerScheduler";
properties["quartz.scheduler.proxy"] = "true";
properties["quartz.threadPool.threadCount"] = "0";
properties["quartz.scheduler.proxy.address"] = address;
return properties;
}
public IScheduler GetScheduler()
{
return Instance;
}
public List<GroupStatus> GetGroups()
{
var results = new List<GroupStatus>();
foreach (var gp in Instance.GetJobGroupNames())
{
results.Add(new GroupStatus()
{
Group = gp,
IsJobGroupPaused = Instance.IsJobGroupPaused(gp),
IsTriggerGroupPaused = Instance.IsTriggerGroupPaused(gp)
});
}
return results;
}
public JobSchedule GetSchedule()
{
var jobKey = new JobKey(JobName, JobGroup);
var trigger = Instance.GetTriggersOfJob(jobKey).FirstOrDefault();
var js = new JobSchedule();
if (trigger != null)
{
js.Name = trigger.Key.Name;
js.Group = trigger.Key.Group;
js.Description = trigger.Description;
js.Priority = trigger.Priority;
js.TriggerType = trigger.GetType().Name;
js.TriggerState = Instance.GetTriggerState(trigger.Key).ToString();
DateTimeOffset? startTime = trigger.StartTimeUtc;
js.StartTime = TimeZone.CurrentTimeZone.ToLocalTime(startTime.Value.DateTime);
var nextFireTime = trigger.GetNextFireTimeUtc();
if (nextFireTime.HasValue)
{
js.NextFire = TimeZone.CurrentTimeZone.ToLocalTime(nextFireTime.Value.DateTime);
}
var previousFireTime = trigger.GetPreviousFireTimeUtc();
if (previousFireTime.HasValue)
{
js.LastFire = TimeZone.CurrentTimeZone.ToLocalTime(previousFireTime.Value.DateTime);
}
}
return js;
}
public List<JobSchedule> GetSchedules()
{
var jcs = new List<JobSchedule>();
foreach (var group in Instance.GetJobGroupNames())
{
var groupMatcher = GroupMatcher<JobKey>.GroupContains(group);
var jobKeys = Instance.GetJobKeys(groupMatcher);
foreach (var jobKey in jobKeys)
{
var triggers = Instance.GetTriggersOfJob(jobKey);
foreach (var trigger in triggers)
{
var js = new JobSchedule();
js.Name = jobKey.Name;
js.Group = jobKey.Group;
js.TriggerType = trigger.GetType().Name;
js.TriggerState = Instance.GetTriggerState(trigger.Key).ToString();
js.Priority = trigger.Priority;
DateTimeOffset? startTime = trigger.StartTimeUtc;
js.StartTime = TimeZone.CurrentTimeZone.ToLocalTime(startTime.Value.DateTime);
DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc();
if (nextFireTime.HasValue)
{
js.NextFire = TimeZone.CurrentTimeZone.ToLocalTime
(nextFireTime.Value.DateTime);
}
DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc();
if (previousFireTime.HasValue)
{
js.LastFire = TimeZone.CurrentTimeZone.ToLocalTime
(previousFireTime.Value.DateTime);
}
jcs.Add(js);
}
}
}
return jcs;
}
public List<JobSchedule> GetSchedules(string groupName)
{
var jcs = new List<JobSchedule>();
var groupMatcher = GroupMatcher<JobKey>.GroupContains(groupName);
var jobKeys = Instance.GetJobKeys(groupMatcher);
foreach (var jobKey in jobKeys)
{
var triggers = Instance.GetTriggersOfJob(jobKey);
foreach (var trigger in triggers)
{
var js = new JobSchedule();
js.Name = jobKey.Name;
js.Description = trigger.Description;
js.Group = jobKey.Group;
js.TriggerType = trigger.GetType().Name;
js.TriggerState = Instance.GetTriggerState(trigger.Key).ToString();
js.Priority = trigger.Priority;
DateTimeOffset? startTime = trigger.StartTimeUtc;
js.StartTime = TimeZone.CurrentTimeZone.ToLocalTime(startTime.Value.DateTime);
DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc();
if (nextFireTime.HasValue)
{
js.NextFire = TimeZone.CurrentTimeZone.ToLocalTime(nextFireTime.Value.DateTime);
}
DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc();
if (previousFireTime.HasValue)
{
js.LastFire = TimeZone.CurrentTimeZone.ToLocalTime
(previousFireTime.Value.DateTime);
}
jcs.Add(js);
}
}
return jcs;
}
public string GetMetaData()
{
var metaData = Instance.GetMetaData();
return string.Format(
"{0}Name: '{1}'{0}Version:
'{2}'{0}ThreadPoolSize: '{3}'{0}IsRemote: '{4}'{0}JobStoreName: '{5}'
{0}SupportsPersistance: '{6}'{0}IsClustered: '{7}'",
Environment.NewLine, metaData.SchedulerName, metaData.Version, metaData.ThreadPoolSize,
metaData.SchedulerRemote, metaData.JobStoreType.Name,
metaData.JobStoreSupportsPersistence,
metaData.JobStoreClustered);
}
public bool UnscheduleJob()
{
var jobKey = new JobKey(JobName, JobGroup);
if (Instance.CheckExists(jobKey))
{
return Instance.UnscheduleJob(new TriggerKey(JobName, JobGroup));
}
return false;
}
public bool UnscheduleAll()
{
foreach (var group in Instance.GetTriggerGroupNames())
{
var groupMatcher = GroupMatcher<JobKey>.GroupContains(group);
var jobKeys = Instance.GetJobKeys(groupMatcher);
foreach (var triggers in jobKeys.Select(jobKey => Instance.GetTriggersOfJob(jobKey)))
{
return Instance.UnscheduleJobs(triggers.Select(t => t.Key).ToList());
}
}
return false;
}
public void DeleteAll()
{
Instance.Clear();
}
public void RescheduleJob()
{
// Build new trigger
var trigger = (ICronTrigger)TriggerBuilder.Create()
.WithIdentity(JobName, JobGroup)
.WithCronSchedule(CronExpression)
.WithPriority(Priority)
//.StartAt(StartAt.ToUniversalTime())
.Build();
Instance.RescheduleJob(new TriggerKey(JobName, JobGroup), trigger);
}
}
}
希望这对您有所帮助…
这是关于使用 Quartz.net 进行企业调度的系列文章中的第六篇。在下一篇文章中,我将介绍如何构建一个示例 MVC 网站,以查看通过 Quartz.Net 调度 Windows 服务调度的作业。感谢您抽出时间阅读这篇博文。如果您喜欢这篇文章,请记得订阅 http://feeds.feedburner.com/TarunArora。敬请期待!