65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.92/5 (5投票s)

2013 年 1 月 23 日

CPOL

2分钟阅读

viewsIcon

30961

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

我收到一个业务需求,需要提供一个自助式网站来进行作业调度。由于我使用过 Quartz.Net,它似乎是调度和处理作业的完美后端引擎。我决定通过一些 Web 方法公开 Quartz.Net 的功能,使用 Web 服务来实现,以便在 Excel、SharePoint、Web 或桌面应用程序中进行消费。在这篇博文中,我将向您展示如何通过 Web 服务公开 Quartz.Net。

image

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 的请求,同时指定计划、优先级等。

     

image

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。敬请期待!

© . All rights reserved.