【问题标题】:Tricky Quartz.NET Scenario棘手的 Quartz.NET 场景
【发布时间】:2012-06-05 04:16:11
【问题描述】:

好的,这里有一点背景。我有一个大型 Web 应用程序 (MVC3),它可以处理各种不重要的事情。我需要这个 Web 应用程序能够在 Oracle 数据库中安排临时 Quartz.NET 作业。然后,我希望稍后通过 windows 服务 执行这些作业。理想情况下,我想安排它们以均匀的间隔运行,但可以选择通过网络应用添加作业。

基本上,所需的架构是这样的一些变体:

Web 应用程序 Quartz.NET 数据库 Quartz.NET Windows 服务

到目前为止我编写的代码:

  • (目前)计划和运行作业的 Windows 服务。从长远来看,这显然不会是这样,但我想知道我是否可以保留它并对其进行修改,使其基本上代表上图中的两个“Quartz.NET”。
  • 网络应用程序(我想细节在这里不是很重要)
  • 作业(实际上只是另一个 Windows 服务)

还有一些重要的注意事项:

  • 它必须从 Windows 服务运行,并且必须通过 Web 应用程序进行调度(以减少 IIS 上的负载)
  • 假设上述项目符号仍然适用,上述架构可以稍微重新排列。

现在,有几个问题:

  1. 这可能吗?
  2. 假设 (1) 通过,你们认为最好的架构是什么?请参阅我编写的第一个项目符号。
  3. 谁能给我一些 Quartz 方法,它们可以帮助我查询数据库,以便在它们已经安排好后执行?

只要这个问题符合条件,就会有赏金。如果问题在此之前以令人满意的方式回答,我仍然会将赏金奖励给答案的发布者。所以,无论如何,如果你在这里给出一个好的答案,你就会得到赏金。

【问题讨论】:

  • 好的,先问几个问题。你认为 Quartz 的工作是什么?我对它进行了一些快速研究,似乎 Quartz.Net 作业是接口的自写实现。 Quartz 项目是执行调度的部分。根据项目主页面,可以使用 ADO.net 将作业存储在 Oracle 数据库中。你真正的问题是什么?
  • 好吧,我只是想弄清楚如何拆分 Quartz 的东西,以便一个实体安排它们,另一个实体执行它们。通常,我会做类似的事情: _scheduler.ScheduleJob(jobDetail, trigger);但这会将其设置为每隔一段时间自动触发一次,具体取决于trigger。我想保留该功能,但也想获得即时安排作业的功能
  • 在我的案例中,quartz 工作是一个 Windows 服务,它可以从系统中清除不必要的文件
  • 这是一个很常见的场景。您使用的是哪个版本? API 在版本之间发生了显着变化,示例代码会有所不同。
  • 2.0.1.100 - 但我想我可以让它工作。尽管如此,我还是希望您能就最好的方式给我任何意见

标签: c# oracle windows-services cron quartz.net


【解决方案1】:

我会尝试按照您提出问题的顺序回答您的问题。

  1. 是的,可以这样做。这实际上是使用 Quartz.Net 的一种常见方式。实际上,您也可以编写一个管理 Quartz.Net 调度程序的 ASP.Net MVC 应用程序。

  2. 架构。理想情况下,在高层次上,您的 MVC 应用程序将使用 Quartz.Net API 与作为 Windows 服务安装在某处的 Quartz.Net 服务器通信。 Quartz.Net 使用远程处理进行远程通信,因此使用远程处理的任何限制都适用(例如 Silverlight 不支持它等)。 Quartz.Net 提供了一种将其安装为开箱即用的 Windows 服务的方法,因此除了将服务本身配置为使用(在您的情况下)AdoJobStore 以及启用远程处理。关于如何正确安装服务需要注意一些事项,所以如果您还没有这样做,请查看at this post

在内部,在您的 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()
  1. 查询 以下是一些从调度程序获取所有作业的示例代码:

    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查看此代码

【讨论】:

  • 现在这是一个很好的答案!它帮助很大。 +1,接受,赏金即将到来。
  • 哦-我想我必须暂时取消您的接受状态,然后才能将赏金放在这里
猜你喜欢
  • 1970-01-01
  • 2011-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-25
  • 1970-01-01
  • 2019-02-22
相关资源
最近更新 更多