root / trunk / hammock / src / net35 / Hammock / Tasks / TimedTask.cs @ 0eea575a
History | View | Annotate | Download (7.4 kB)
1 |
using System; |
---|---|
2 |
using System.Diagnostics; |
3 |
using System.Threading; |
4 |
using Hammock.Web; |
5 |
|
6 |
#if SILVERLIGHT |
7 |
using Hammock.Silverlight.Compat; |
8 |
#endif |
9 |
namespace Hammock.Tasks |
10 |
{ |
11 |
public class TimedTask : ITimedTask |
12 |
{ |
13 |
protected readonly object Lock = new object(); |
14 |
protected bool Active; |
15 |
protected int Iterations; |
16 |
protected Timer Timer; |
17 |
protected bool ContinueOnError; |
18 |
|
19 |
public Action<bool> Action { get; protected set; } |
20 |
public Exception Exception { get; protected set; } |
21 |
public TimeSpan DueTime { get; protected set; } |
22 |
public TimeSpan Interval { get; protected set; } |
23 |
internal WebQueryAsyncResult AsyncResult { get; set; } |
24 |
public event Action<TimedTask, EventArgs> Stopped; |
25 |
|
26 |
public TimedTask(TimeSpan due, |
27 |
TimeSpan interval, |
28 |
int iterations, |
29 |
bool continueOnError, |
30 |
Action<bool> action) : |
31 |
this(due, interval, iterations, action) |
32 |
{ |
33 |
ContinueOnError = continueOnError; |
34 |
} |
35 |
|
36 |
public TimedTask(TimeSpan due, |
37 |
TimeSpan interval, |
38 |
int iterations, |
39 |
Action<bool> action) |
40 |
{ |
41 |
DueTime = due; |
42 |
Interval = interval; |
43 |
Iterations = iterations; |
44 |
Action = action; |
45 |
} |
46 |
|
47 |
protected virtual void Start(bool continueOnError) |
48 |
{ |
49 |
var count = 0; |
50 |
Timer = new Timer(state => |
51 |
{ |
52 |
try |
53 |
{ |
54 |
Action(false); |
55 |
count++; |
56 |
if (Iterations > 0 && count > Iterations) |
57 |
{ |
58 |
Stop(); |
59 |
} |
60 |
} |
61 |
catch (Exception ex) |
62 |
{ |
63 |
Exception = ex; |
64 |
if (!continueOnError) |
65 |
{ |
66 |
Stop(); |
67 |
} |
68 |
} |
69 |
}, null, DueTime, Interval); |
70 |
} |
71 |
|
72 |
|
73 |
public virtual void Stop() |
74 |
{ |
75 |
if (Active) |
76 |
{ |
77 |
lock (Lock) |
78 |
{ |
79 |
if (Active) |
80 |
{ |
81 |
Active = false; |
82 |
Timer.Change(-1, -1); |
83 |
OnStopped(EventArgs.Empty); |
84 |
if (AsyncResult != null) |
85 |
{ |
86 |
AsyncResult.Signal(); |
87 |
} |
88 |
} |
89 |
} |
90 |
} |
91 |
} |
92 |
|
93 |
public virtual void Start() |
94 |
{ |
95 |
if (!Active) |
96 |
{ |
97 |
lock (Lock) |
98 |
{ |
99 |
if (!Active) |
100 |
{ |
101 |
Active = true; |
102 |
if (Timer != null) |
103 |
{ |
104 |
Timer.Change(DueTime, Interval); |
105 |
} |
106 |
else |
107 |
{ |
108 |
Start(ContinueOnError); |
109 |
} |
110 |
} |
111 |
} |
112 |
} |
113 |
} |
114 |
|
115 |
public virtual void Start(TimeSpan dueTime, TimeSpan interval) |
116 |
{ |
117 |
if (!Active) |
118 |
{ |
119 |
lock (Lock) |
120 |
{ |
121 |
if (!Active) |
122 |
{ |
123 |
DueTime = dueTime; |
124 |
Interval = interval; |
125 |
Timer.Change(DueTime, Interval); |
126 |
} |
127 |
} |
128 |
} |
129 |
} |
130 |
protected virtual void OnStopped(EventArgs e) |
131 |
{ |
132 |
if (Stopped != null) |
133 |
{ |
134 |
Stopped(this, e); |
135 |
} |
136 |
} |
137 |
|
138 |
public virtual void Dispose() |
139 |
{ |
140 |
Stop(); |
141 |
Timer.Dispose(); |
142 |
} |
143 |
} |
144 |
|
145 |
#if !SILVERLIGHT |
146 |
[Serializable] |
147 |
#endif |
148 |
public class TimedTask<T> : TimedTask, ITimedTask<T> |
149 |
{ |
150 |
public TimedTask(TimeSpan due, |
151 |
TimeSpan interval, |
152 |
int iterations, |
153 |
bool continueOnError, |
154 |
Action<bool> action, |
155 |
IRateLimitingRule<T> rateLimitingRule) : |
156 |
base(due, interval, iterations, action) |
157 |
{ |
158 |
RateLimitingRule = rateLimitingRule; |
159 |
ContinueOnError = continueOnError; |
160 |
} |
161 |
|
162 |
protected override void Start(bool continueOnError) |
163 |
{ |
164 |
var count = 0; |
165 |
Timer = new Timer(state => |
166 |
{ |
167 |
try |
168 |
{ |
169 |
//[JD] |
170 |
//only allow the task to run once concurrently. |
171 |
//if a second task attempts to enter the monitor while |
172 |
//the first one is still running, simply drop it |
173 |
if (Monitor.TryEnter(Lock)) |
174 |
{ |
175 |
try |
176 |
{ |
177 |
#if TRACE |
178 |
Trace.WriteLine("Running a periodic task"); |
179 |
#endif |
180 |
var skip = RateLimitingRule.ShouldSkipForRateLimiting(); |
181 |
#if TRACE |
182 |
Trace.WriteLine(string.Format("{0} Evaluated rate limiting predicate and result was {1}", |
183 |
DateTime.Now.ToShortTimeString(), |
184 |
skip ? "'skip'" : "'don't skip'")); |
185 |
#endif |
186 |
Action(skip); |
187 |
var newInterval = RateLimitingRule.CalculateNewInterval(); |
188 |
#if TRACE |
189 |
Trace.WriteLine(string.Format("{0} Calculated new interval for throttled task and result was: {1}", |
190 |
DateTime.Now.ToShortTimeString(), |
191 |
newInterval.HasValue ? newInterval.Value.ToString() : "'no change'")); |
192 |
#endif |
193 |
count++; |
194 |
|
195 |
if (Iterations > 0 && count >= Iterations) |
196 |
{ |
197 |
Stop(); |
198 |
} |
199 |
else if (newInterval.HasValue) |
200 |
{ |
201 |
Timer.Change((int)newInterval.Value.TotalMilliseconds, (int)newInterval.Value.TotalMilliseconds); |
202 |
} |
203 |
} |
204 |
finally |
205 |
{ |
206 |
Monitor.Exit(Lock); |
207 |
} |
208 |
} |
209 |
else |
210 |
{ |
211 |
#if TRACE |
212 |
Trace.WriteLine("Skipping recurring task because the previous iteration is still active"); |
213 |
#endif |
214 |
Action(true); |
215 |
} |
216 |
} |
217 |
catch (Exception ex) |
218 |
{ |
219 |
Exception = ex; |
220 |
if (!continueOnError) |
221 |
{ |
222 |
Stop(); |
223 |
} |
224 |
} |
225 |
}, null, DueTime, Interval); |
226 |
} |
227 |
|
228 |
#region ITimedTask Members |
229 |
|
230 |
public virtual bool RateLimited |
231 |
{ |
232 |
get { return RateLimitingRule != null; } |
233 |
} |
234 |
|
235 |
public IRateLimitingRule<T> RateLimitingRule { get; set; } |
236 |
|
237 |
public override void Dispose() |
238 |
{ |
239 |
base.Dispose(); |
240 |
} |
241 |
#endregion |
242 |
} |
243 |
} |