发布于 2021-04-13 22:06:44
我有一个类似的要求,我找不到一个符合RFC 5545的库来与Quartz调度程序一起工作,最后我按照这一建议实现了一个自定义触发器
在我的例子中,我们使用控件来填充RRULE,但是您也可以对iCal.Net库进行同样的操作。这里并不是完整的实现,但它将使您开始工作,代码是未测试的。
另一个注意事项:如果尝试使用Telerik RecurrenceRule解析它,"FREQ=WEEKLY;BYDAY=MO;INTERVAL=2“可能会失败,因为它缺少DTSTART、DTEND等。这是一个不会失败的重复规则字符串的示例:"DTSTART:20210309T050000Z\r\nDTEND:20210309T060000Z\r\nRRULE:FREQ=WEEKLY;BYDAY=TU;INTERVAL=1"。
您需要实现ITrigger接口。其中许多内容可以从CroneTriggerImpl类中复制和修改。
public interface IRRuleTrigger : ITrigger
{
string RecurrenceRuleString { get; set; }
} 然后,您需要从AbstractTrigger继承的实现类。
public class MyTriggerImpl: AbstractTrigger, IRRuleTrigger
{
//implement all members here. Look at CronTriggerImpl class in Quartz.Net source. I'm pasting some of the implementation code but not all.
//...
private RecurrenceRule rRule;
/// <summary>
/// Gets or sets the RRULE expression string.
/// </summary>
/// <value>The expression string.</value>
public string RecurrenceRuleString
{
set
{
TimeZoneInfo originalTimeZone = TimeZone;
var success = RecurrenceRule.TryParse(value, out var parsedRule);
if(success) rRule = parsedRule ;// RecurrenceRule(value!);
}
get => rRule?.ToString();
}
/// <summary>
/// Gets or sets the RRULE expression string.
/// </summary>
/// <value>The expression string like RRULE:FREQ=WEEKLY;BYDAY=MO;INTERVAL=2.</value>
public string RecurrenceRuleString
{
set
{
TimeZoneInfo originalTimeZone = TimeZone;
var success = RecurrenceRule.TryParse(value, out var parsedRule);
if(success) rRule = parsedRule ;// RecurrenceRule(value!);
}
get => rRule?.ToString();
}
////////////////////////////////////////////////////////////////////////////
//
// Computation Functions
//
////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Gets the next time to fire after the given time.
/// </summary>
/// <param name="afterTime">The time to compute from.</param>
/// <returns></returns>
protected DateTimeOffset? GetTimeAfter(DateTimeOffset afterTime)
{
return rRule?.HasOccurrences == true ?
rRule?.Occurrences.Where(o => o > afterTime).Min()
: null;
}
/// <summary>
/// Returns the time before the given time
/// that this <see cref="IRRuleTrigger" /> will fire.
/// </summary>
/// <param name="date">The date.</param>
/// <returns></returns>
protected DateTimeOffset? GetTimeBefore(DateTimeOffset? date)
{
return rRule?.HasOccurrences == true ?
rRule?.Occurrences.Where(o=> o < date).Max()
: null;
}
}
public class RRuleScheduleBuilder : ScheduleBuilder<IRRuleTrigger>
{
private int misfireInstruction = MisfireInstruction.SmartPolicy;
private RecurrenceRule recurrenceRule;
public override IMutableTrigger Build()
{
MyTriggerImpl myTriggerImpl = new MyTriggerImpl();
myTriggerImpl.MisfireInstruction = misfireInstruction;
myTriggerImpl.RecurrenceRuleString = this.recurrenceRule.ToString();
return myTriggerImpl;
}
/// <summary>
/// Create a RRuleScheduleBuilder with the given string expression - which
/// is presumed to be valid expression (and hence only a RuntimeException
/// will be thrown if it is not).
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="recurrenceRuleString">the RRule expression to base the schedule on.</param>
/// <returns>the new RRuleScheduleBuilder</returns>
public static RRuleScheduleBuilder RecurrenceRuleSchedule(string recurrenceRuleString)
{
var success = RecurrenceRule.TryParse(recurrenceRuleString, out var rRule);
if(!success) throw new ArgumentException($"Recurrence Rule String ({recurrenceRuleString}) is invalid.");
return new RRuleScheduleBuilder(rRule);
}
protected RRuleScheduleBuilder(RecurrenceRule rule)
{
this.recurrenceRule = rule ?? throw new ArgumentNullException(nameof(rule), "recurrenceRule cannot be null");
}
}
/// <summary>
/// Extension methods that attach <see cref="RRuleScheduleBuilder" /> to <see cref="TriggerBuilder" />.
/// </summary>
public static class RRuleScheduleTriggerBuilderExtensions
{
public static TriggerBuilder WithRRuleSchedule(this TriggerBuilder triggerBuilder, string recurrenceRuleString)
{
RRuleScheduleBuilder builder = RRuleScheduleBuilder.RecurrenceRuleSchedule(recurrenceRuleString);
return triggerBuilder.WithSchedule(builder);
}
public static TriggerBuilder WithRRuleSchedule(this TriggerBuilder triggerBuilder, string recurrenceRuleString, Action<RRuleScheduleBuilder> action)
{
RRuleScheduleBuilder builder = RRuleScheduleBuilder.RecurrenceRuleSchedule(recurrenceRuleString);
action(builder);
return triggerBuilder.WithSchedule(builder);
}
}实现之后,您可以像这样创建和使用触发器:
// Grab the Scheduler instance from the Factory
StdSchedulerFactory factory = new StdSchedulerFactory();
var scheduler = await factory.GetScheduler();
await scheduler.Start();
var job = JobBuilder.Create<MyBusinessClassThatImplementsIJobInterface>()
.WithIdentity("someIdentity", "someGroupName")
.Build();
var trigger = (IRRuleTrigger)TriggerBuilder.Create()
.WithIdentity("someName", "myGroup")
.WithRRuleSchedule(rule.ToString())
.Build();
await scheduler.ScheduleJob(job, trigger);https://stackoverflow.com/questions/66656860
复制相似问题