Statistics
| Branch: | Revision:

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
}