-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathRecurringTask.cs
135 lines (106 loc) · 4.09 KB
/
RecurringTask.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
using System;
using System.Threading.Tasks;
using Gofer.NET.Utils;
using NCrontab;
using Newtonsoft.Json;
namespace Gofer.NET
{
[JsonObject(MemberSerialization.OptIn)]
public class RecurringTask
{
public string LockKey => $"{nameof(RecurringTask)}::{TaskKey}::ScheduleLock";
[JsonProperty]
public string TaskKey { get; private set; }
[JsonProperty]
public DateTime StartTime { get; private set; }
[JsonProperty]
public DateTime FirstRunTime { get; private set; }
[JsonProperty]
public TaskInfo TaskInfo { get; private set; }
[JsonProperty]
public TimeSpan? Interval { get; private set; }
[JsonProperty]
public string Crontab { get; private set; }
public RecurringTask() { }
public RecurringTask(
TaskInfo taskInfo,
TimeSpan interval,
string taskKey) : this(taskInfo, taskKey)
{
Interval = interval;
FirstRunTime = GetNextRunTime(DateTime.UtcNow);
}
public RecurringTask(
TaskInfo taskInfo,
string crontab,
string taskKey) : this(taskInfo, taskKey)
{
ValidateCrontab(crontab);
Crontab = crontab;
FirstRunTime = GetNextRunTime(DateTime.UtcNow);
}
private RecurringTask(TaskInfo taskInfo, string taskKey)
{
TaskInfo = taskInfo;
StartTime = DateTime.UtcNow;
TaskKey = taskKey;
}
public DateTime GetNextRunTime(DateTime baseTime)
{
if (baseTime == null)
{
throw new ArgumentException("baseTime must not be null.");
}
if (Interval != null)
{
if (baseTime < StartTime)
{
throw new ArgumentException("baseTime cannot be less than task StartTime");
}
var difference = (baseTime - StartTime).TotalMilliseconds;
var intervalMs = Interval.Value.TotalMilliseconds;
var elapsedIntervals = difference / intervalMs;
var targetOffsetMs = (elapsedIntervals + 1) * intervalMs;
var offsetFromBase = TimeSpan.FromMilliseconds(targetOffsetMs - difference);
return (baseTime + offsetFromBase);
}
if (Crontab != null)
{
var crontabSchedule = CrontabSchedule.Parse(Crontab, new CrontabSchedule.ParseOptions() { IncludingSeconds = true });
var nextOccurence = crontabSchedule.GetNextOccurrence(baseTime);
return nextOccurence;
}
throw new Exception("Crontab and Interval both null. Unexpected condition.");
}
public long GetNextRunTimestamp(DateTime baseTime)
{
return GetNextRunTime(baseTime).ToUnixTimeMilliseconds();
}
private void ValidateCrontab(string crontab)
{
try
{
var schedule = CrontabSchedule.Parse(crontab, new CrontabSchedule.ParseOptions{IncludingSeconds = true});
schedule.GetNextOccurrence(DateTime.UtcNow);
}
catch (Exception ex)
{
throw new Exception("Crontab is invalid. See the inner exception for details.", ex);
}
}
public bool IsEquivalent(RecurringTask comparisonRecurringTask)
{
if (comparisonRecurringTask == null)
{
throw new ArgumentException("comparisonRecurringTask must not be null");
}
if (comparisonRecurringTask.TaskKey != TaskKey)
{
throw new Exception("Cannot compare with a recurringTask with a different TaskKey.");
}
return TaskInfo.IsEquivalent(comparisonRecurringTask.TaskInfo)
&& Interval == comparisonRecurringTask.Interval
&& string.Equals(Crontab, comparisonRecurringTask.Crontab, StringComparison.Ordinal);
}
}
}