5

我正在尝试将 Quartz.NET 实现为 C# 中的 Windows 服务。当我期望它们触发时,我的工作没有触发......实际上,据我所知?

我的“我的工作”计划在“每分钟”之后的下一个偶数分钟开始运行。但是,当下一分钟到来时,我似乎无法判断是否有任何实际运行。

我会假设当我的作业运行时,会在作业执行时弹出一个 CLI 窗口,并且控制台操作将是可见的,(我什Console.ReadKey()至在其中放了一个以确保窗口不会打开和关闭这么快我看不到它),但据我所知,时间表根本不执行作业。

我注意到所有时间都是 UTC 时间,并且StartTimeUtc将设置为 UTC 时间,距离我的本地计算机时间 +6 小时,但我还假设 Quartz 调度程序通过从我的 TimeZone 设置计算执行时间来处理它,尽管我无法确认或确认我的日程安排的实际时间。

我想有一些方法可以设置 Common Logging 程序集并利用它来帮助我了解我的状态,但我还没有弄清楚如何处理它以启用任何类型的日志以获取来自我的 Windows 服务的反馈,除了从写入我为它创建的事件日志。

我的 Windows 服务的 OnStart 功能

protected override void OnStart(string[] args)
    {
        eventLog.WriteEntry("--- STARTING eLoyalty Scheduler Service ---");

        // construct a scheduler factory
        ISchedulerFactory schedFact = new StdSchedulerFactory();

        // get a scheduler
        IScheduler sched = schedFact.GetScheduler();

        // construct job info
        JobDetail jobDetail = new JobDetail("eLoyaltySchedulerService", null, typeof(PortalSchedulerJob));
        jobDetail.JobDataMap["jobSays"] = "eLoyalty Scheduler Service Executing!";
        jobDetail.JobDataMap["myStateData"] = new ArrayList(); 

        // fire every minute
        Trigger trigger = TriggerUtils.MakeMinutelyTrigger();

        // start on the next even minute
        trigger.StartTimeUtc = TriggerUtils.GetEvenMinuteDate(DateTime.UtcNow);

        // name it
        trigger.Name = "NextEvenMinute";

        // schedule it
        sched.ScheduleJob(jobDetail, trigger);

        // start the schedule
        sched.Start();

        eventLog.WriteEntry("--- STARTED eLoyalty Scheduler Service ---");
    }

我的 Job 的 Execute() 函数如下:

public void Execute(JobExecutionContext context)
    {
        try
        {
            string instName = context.JobDetail.Name;
            string instGroup = context.JobDetail.Group;
            JobDataMap dataMap = context.MergedJobDataMap;
            string jobSays = dataMap.GetString("jobSays");
            ArrayList state = (ArrayList)dataMap["myStateData"];
            state.Add(DateTime.UtcNow);

            Console.WriteLine("Instance {0} of PortalSchedulerJob says: {1} @ {2}", instName, jobSays, DateTime.UtcNow);
            Console.ReadKey();
        }
        catch (JobExecutionException Ex)
        {
            throw Ex;
        }
    }

如果您能帮我弄清楚如何解决我的实际日程安排活动,我也许可以自己解决这个问题......?

4

5 回答 5

9

在 Quartz.NET 任务中,您只能引发 JobExecutionException 异常:Quartz.net-第 3 课

Job.Execute(..) 方法 最后,我们需要告诉您 IJob.Execute(..) 方法的一些细节。允许从 execute 方法抛出的唯一异常类型是 JobExecutionException。因此,您通常应该使用“try-catch”块包装执行方法的全部内容。您还应该花一些时间查看 JobExecutionException 的文档,因为您的作业可以使用它来为调度程序提供各种指令,以了解您希望如何处理异常。

代替:

catch (JobExecutionException Ex)
{
   throw Ex;
}

做这样的事情:

catch (Exception err)
{
    // Only allow JobExecutionException exceptions to be thrown...
    throw new Quartz.JobExecutionException(err);
}

然后,您可以集中处理异常:

_globalJobListener = new GlobalJobListener();
sched.AddGlobalJobListener(_globalJobListener);


public class GlobalJobListener : Quartz.IJobListener
{
    public GlobalJobListener()
    {
    }

    public virtual string Name
    {
        get { return "MainJobListener"; }
    }

    public virtual void JobToBeExecuted(JobExecutionContext context)
    {       
    }

    public virtual void JobWasExecuted(JobExecutionContext inContext, JobExecutionException inException)
    {
        if (inException != null)
        {
            // Log/handle error here
        }
    }


    public virtual void JobExecutionVetoed(JobExecutionContext inContext)
    {

    }
}
于 2010-11-25T08:10:57.663 回答
2

调试时,您始终可以在控制台中运行 Windows 服务:

static class Program
{
    static void Main()
    {
        var servicesToRun = new ServiceBase[] 
            { 
                new CassetteDeckService() 
            };

        if (Environment.UserInteractive)
        {
            var type = typeof(ServiceBase);
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
            var method = type.GetMethod("OnStart", flags);

            foreach (var service in servicesToRun)
            {
                method.Invoke(service, new object[] { null });
            }

            Console.WriteLine("Service Started!");
            Console.ReadLine();

            method = type.GetMethod("OnStop", flags);

            foreach (var service in servicesToRun)
            {
                method.Invoke(service, null);
            }
            Environment.Exit(0);
        }
        else
        {
            ServiceBase.Run(servicesToRun);
        }
    }
}

只需确保在您的 Windows 服务项目的属性中将应用程序类型更改为控制台应用程序(这不会影响它在不以交互模式运行时作为 Windows 服务运行)。

于 2013-05-08T14:43:20.313 回答
0

我们遇到了一些触发器失灵的问题。我添加了一个全局触发器侦听器来捕获与触发作业相关的事件,并提供调试问题所需的信息。

我们还通过 Common.Logging 连接了 NLog 来捕捉 Quartz 的内部日志(你可能注意到我们自己使用了Simple Logging Facade,所以这里也配置了这个组件)。这是我们的应用程序配置,希望可以让您快速入门:

<?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" />
        <section name="slf" type="Slf.Config.SlfConfigurationSection, slf"/>
        <sectionGroup name="common">
            <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
        </sectionGroup>
    </configSections>


    <quartz>
        <add key="quartz.threadPool.threadCount" value="20" />
        <add key="quartz.jobStore.misfireThreshold" value="420000" /><!-- 7 minutes -->
    </quartz>


    <slf>
        <factories>
            <factory name="nlog" type="SLF.NLogFacade.NLogLoggerFactory, SLF.NLogFacade"/>
        </factories>

        <loggers>
            <logger factory="nlog"/>
        </loggers>
    </slf>

    <common>
        <logging>
            <factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog">
                <arg key="configType" value="FILE" />
                <arg key="configFile" value="~/NLog.config" />
            </factoryAdapter>
        </logging>
    </common>

</configuration>
于 2010-11-24T17:24:03.953 回答
0

感谢大家的输入......不幸的是,我无法让任何这些工作,但是当我将事件记录器添加到我的作业执行功能时,我发现它按预期每分钟每分钟写入事件日志。

我猜Console.WriteLine()and Console.ReadKey()funcs 在 Windows 服务环境中什么都不做?

注意:他们做某事,但在后台作为服务而不是在控制台窗口中运行......

于 2010-11-29T21:09:03.613 回答
0

如果您想调试您的工作,请保持打开 Visual Studio,在您的工作代码中输入:

System.Diagnostics.Debugger.Launch();

这将允许您附加到 Visual Studio 中的调试器,您可以看到发生了什么。

或者,如果您想让常用的日志记录正常工作,请给我发送消息,因为我的 Windows 服务中一切正常。

于 2013-06-09T21:55:30.947 回答