在我正在研究的C#项目中,我遇到了Quartz(版本2.2.4)的一个相当令人困惑的问题,尽管我付出了最大的努力,但我还是无法解决问题。
该项目需要独立安排几个不同的任务;在这种情况下,我写了一个专门用于处理24小时循环工作的课程。对于需要安排的每个任务,该类应该被实例化一次。
以下是有问题的对象:
namespace ProjectFront.Utilities {
public class QuartzScheduler {
public const string QB_TRIGGER = "qbTrigger";
public const string QB_JOB = "qbJob";
public const string QB_GROUP = "qbGroup";
private IScheduler scheduler;
private ITrigger trigger;
private IJobDetail job;
private JobKey jobKey;
public QuartzScheduler(IJob controller, string triggerId, string jobId, string jobGroup, int syncHour, int syncMinute) {
StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
schedulerFactory.Initialize();
jobKey = new JobKey(jobId, jobGroup);
syncHour = getHour(syncHour);
syncMinute = getMin(syncMinute);
scheduler = schedulerFactory.GetScheduler();
scheduler.Start();
job = JobBuilder.Create(controller.GetType())
.StoreDurably()
.WithIdentity(jobKey)
.Build();
trigger = TriggerBuilder.Create()
.WithIdentity(triggerId)
.ForJob(jobKey)
.StartNow()
.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(syncHour, syncMinute))
.Build();
scheduler.ScheduleJob(job, trigger);
scheduler.Start();
}
public void Reschedule(int syncHour, int syncMinute) {
scheduler.Standby();
syncHour = getHour(syncHour);
syncMinute = getMin(syncMinute);
TriggerKey triggerKey = trigger.Key;
trigger = TriggerBuilder.Create()
.WithIdentity(triggerKey)
.ForJob(jobKey)
.StartNow()
.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(syncHour, syncMinute))
.Build();
scheduler.RescheduleJob(triggerKey, trigger);
scheduler.Start();
}
public IScheduler GetScheduler() {
return scheduler;
}
public ITrigger GetTrigger() {
return trigger;
}
private int getHour(int num) {
if (num < 4) {
return num + 20;
}
return num - 4;
}
private int getMin(int num) {
while (num >= 60) {
num -= 60;
}
return num;
}
}
}
我编写了几个NUnit测试,以确保对象中的所有内容都能正常工作。它通过其中两个,但总是失败第三个;这项工作肯定存在,甚至可以重新安排,但是在调用TriggerJob()
时无法激活。重新安排它,然后等待它同样开火也无法工作。
这些是测试:
namespace UnitTestProject.BackEnd_UnitTests.Util {
public class ControllerStub : IJob{
public ControllerStub() { }
public void Execute(IJobExecutionContext context)
{
Console.WriteLine("Fired!");
Console.WriteLine(DateTime.Now.ToString());
}
}
[TestFixture]
public class QBSchedulerTest {
public static int fired = 0;
private QuartzScheduler target;
private JobKey expectedJob;
private ControllerStub dummy;
[TestFixtureSetUp]
public void fixture() {
colAlias.LogManager.Adapter = new colAlias.Simple.TraceLoggerFactoryAdapter { Level = colAlias.LogLevel.Info };
expectedJob = new JobKey(QuartzScheduler.QB_JOB, QuartzScheduler.QB_GROUP);
}
[SetUp]
public void setup() {
dummy = new ControllerStub();
target = new QuartzScheduler(dummy, QuartzScheduler.QB_TRIGGER, QuartzScheduler.QB_JOB, QuartzScheduler.QB_GROUP, 0, 1);
}
[TearDown]
public void teardown() {
target.GetScheduler().Clear();
}
[Test]
public void HasBeenScheduled() {
Assert.IsTrue(target.GetScheduler().CheckExists(expectedJob));
Assert.IsTrue(target.GetScheduler().IsStarted);
Assert.IsTrue(target.GetScheduler().GetJobGroupNames().Contains(QuartzScheduler.QB_GROUP));
Assert.True(target.GetTrigger().JobKey.Equals(expectedJob));
Assert.Null(target.GetTrigger().GetPreviousFireTimeUtc());
Assert.IsTrue(target.GetTrigger().GetMayFireAgain());
}
[Test]
public void CanBeRescheduled() {
target.Reschedule(1, 0);
string actual = target.GetTrigger().GetNextFireTimeUtc().ToString();
Assert.IsTrue(actual.Contains("1:00:00 AM"));
}
[Test]
public void CanBeExecuted() {
DateTimeOffset expected = DateTimeOffset.Now;
expected.AddMinutes(1);
Assert.IsTrue(target.GetScheduler().CheckExists(expectedJob));
target.Reschedule(expected.Hour, expected.Minute);
target.GetScheduler().TriggerJob(expectedJob);
Thread.Sleep(60500);
Assert.NotNull(target.GetScheduler().GetTrigger(new TriggerKey(QuartzScheduler.QB_TRIGGER)).GetPreviousFireTimeUtc());
}
}
}
失败的唯一原因是我找不到作业无法激活的原因是调度程序无法找到默认构造函数。我已尝试使用给定方法和默认构造函数进行测试,但无论如何测试都失败了。
我不知道为什么会这样。任何人都可以提供可能的建议吗?
编辑:
使事情变得更奇怪,向Console.Write()
方法添加Execute()
语句会导致消息显示在控制台窗口中,但FakeController.fired
值的更改不会持续存在,并且{ {1}}仍然返回null!
编辑:(更新的代码)
我已经将问题缩小到了构建Trigger对象的范围; GetTrigger().GetPreviousFiringTimeUtc()
将导致target.GetScheduler.TriggerJob(expectedJob)
消息出现(尽管静态变量不会更改值)。但是,如图所示安排作业将导致触发器永远不会触发。
答案 0 :(得分:0)
问题在于触发器的调度机制的构造没有正确编写。 ChronScheduleBuilder
要么无法正常工作,要么以错误的方式实施。
最终的解决方案是用一个简单的间隔调度程序替换它,如下所示:
trigger = TriggerBuilder
.Create()
.WithIdentity(triggerKey)
.ForJob(jobKey)
.WithSchedule(SimpleScheduleBuilder
.Create()
.WithIntervalInHours(24)
.RepeatForever())
.StartAt(
new DateTimeOffset(
new DateTime(
DateTimeOffset.Now.Year,
DateTimeOffset.Now.Month,
DateTimeOffset.Now.Day,
syncHour,
syncMinute,
0,
DateTimeKind.Local)))
.Build();