Quartz.NET - 作业不运行?

发布于 2024-10-04 09:46:05 字数 2463 浏览 5 评论 0原文

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

我的工作计划在下一个偶数分钟开始运行,并“每分钟”运行一次。然而,当下一分钟到来时,我似乎无法判断是否有任何东西真正运行。

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

我注意到所有时间都是 UTC,并且 StartTimeUtc 将设置为 UTC 时间,距我的本地计算机时间 +6 小时,但我还假设 Quartz 调度程序会处理该时间通过根据我的时区设置计算执行时间,尽管我没有办法确认这一点,或者确认我的日程设置的实际时间。

我想有某种方法可以设置通用日志记录程序集并利用它来帮助我了解我的状态,但我还没有弄清楚如何使用它来启用任何类型的日志以获取来自我的 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 ---");
    }

我的作业的 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;
        }
    }

如果您能帮助我弄清楚如何对我的实际计划活动进行故障排除,我也许可以自己解决这个问题...?

I'm attempting to implement Quartz.NET as a Windows Service in C#. My jobs are not triggering when I expect them to trigger... at all, actually, as far as I can tell?

I have My Job schedule running starting on the next even minute after the and running "minutely". However, when the next minute comes, I cannot seem to tell if anything actually runs.

I would assume that when my job runs, a CLI window would pop on job execution, and the Console operations would be visible, (I even put a Console.ReadKey() in there to ensure the window isn't opening and closing so fast I can't see it), but as far as I can tell the schedule is simply not executing jobs.

I noticed that all the times are in UTC, and that the StartTimeUtc will be set to the UTC time which is +6 hours from my local computer time, but I would also assume that the Quartz scheduler handles that by calculating execution time from my TimeZone setting, though I have no way that I know of to confirm that, or to confirm the ACTUAL times that my schedule is set for.

I imagine there's some way to setup the Common Logging assembly and utilize it to help me know what my status is, but I have yet to figure out what to do with that to enable a log of any sort for feedback from my Windows Service, aside from writing to the event log I created for it.

My OnStart function of my windows service

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 ---");
    }

My Job's Execute() function is as follows:

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;
        }
    }

If you can help me figure out how to troubleshoot my ACTUAL schedule activity, I may be able to solve this on my own... ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

未蓝澄海的烟 2024-10-11 09:46:05

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

Job.Execute(..) 方法最后,我们
需要通知您一些细节
IJob.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)
    {

    }
}

In Quartz.NET tasks, you must only raise JobExecutionException exceptions:
Quartz.net- Lesson 3:

The Job.Execute(..) Method Finally, we
need to inform you of a few details of
the IJob.Execute(..) method. The only
type of exception that you are allowed
to throw from the execute method is
the JobExecutionException. Because of
this, you should generally wrap the
entire contents of the execute method
with a 'try-catch' block. You should
also spend some time looking at the
documentation for the
JobExecutionException, as your job can
use it to provide the scheduler
various directives as to how you want
the exception to be handled.

Instead of:

catch (JobExecutionException Ex)
{
   throw Ex;
}

Do something like this:

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

You can then handle the Exception centrally:

_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)
    {

    }
}
屋檐 2024-10-11 09:46:05

调试时,您始终可以在控制台中运行 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 服务运行)不以交互模式运行)。

You could always run your Windows service in the console when you're debugging:

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);
        }
    }
}

Just make sure to change the application type to Console Application in the properties of your Windows service project (this won't affect it running as a Windows service when it is not run in interactive mode).

花桑 2024-10-11 09:46:05

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

我猜 Console.WriteLine()Console.ReadKey() 函数在 Windows 服务环境中什么也不做?

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

Thanks for the input everyone... I couldn't get any of this to work, unfortunately, but when I added an event logger to my Job execution function, I found that it wrote to the eventlog every minute on the minute as expected.

I guess the Console.WriteLine() and Console.ReadKey() funcs do nothing in a windows service environment?

NOTE: They do something, but in the background running as a service rather than in a console window...

画▽骨i 2024-10-11 09:46:05

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

System.Diagnostics.Debugger.Launch();

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

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

if you want to debug your job keep visual studio open, in your job code put :

System.Diagnostics.Debugger.Launch();

that will allow you to attach to the debugger in visual studio and you can see what is going on.

alternatively, if you want to get common logging working, send me a message as I have it all working fine in my windows service.

此岸叶落 2024-10-11 09:46:05

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

我们还通过 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>

We had some problems with triggers misfiring. I added a global trigger listener to catch events related to the firing of jobs and that provided the information needed to debug the issue.

We also hooked up NLog through Common.Logging to catch Quartz's internal logging (you may notice we use Simple Logging Facade ourselves, so that component is also configured here). Here's our app config, hopefully that can jump start you:

<?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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文