我正在尝试在C#中将Quartz.NET实现为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 ---");
}
My 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;
}
}
如果您可以帮我弄清楚如何解决我的ACTUAL日程安排活动,我可以自己解决这个问题吗?
答案 0 :(得分:9)
在Quartz.NET任务中,您只能引发JobExecutionException异常: Quartz.net- Lesson 3:
Job.Execute(..)方法最后,我们 需要告诉你一些细节 IJob.Execute(..)方法。唯一的 允许的异常类型 从execute方法中抛出是 JobExecutionException。因为 这个,你通常应该包装 execute方法的全部内容 带有'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)
{
}
}
答案 1 :(得分: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服务运行)。
答案 2 :(得分:0)
我们遇到了触发器失火的一些问题。我added a global trigger listener捕获与解雇工作相关的事件,并提供调试问题所需的信息。
我们还通过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>
答案 3 :(得分:0)
感谢大家的投入......遗憾的是,我无法使用任何此类功能,但是当我将一个事件记录器添加到我的Job执行功能时,我发现它每分钟都会写入事件日志如预期的那样。
我想Console.WriteLine()
和Console.ReadKey()
funcs在Windows服务环境中什么都不做?
注意:他们做了一些事情,但在后台作为服务运行而不是在控制台窗口中运行......
答案 4 :(得分:0)
如果你想调试你的工作,请在你的工作代码中打开visual studio:
System.Diagnostics.Debugger.Launch();
这将允许您附加到visual studio中的调试器,您可以看到正在发生的事情。
或者,如果你想让常见的日志记录工作,请给我发一条消息,因为我在Windows服务中一切正常。