Mercurial > pub > ImplabNet
comparison Implab/Components/PollingRunnableComponent.cs @ 202:2651cb9a4250 v2
Implemented PollingRunnableComponent
author | cin |
---|---|
date | Tue, 18 Oct 2016 01:03:49 +0300 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
201:d7cd7a83189a | 202:2651cb9a4250 |
---|---|
1 using System; | |
2 using System.Threading; | |
3 using Implab.Diagnostics; | |
4 | |
5 namespace Implab.Components { | |
6 public class PollingRunnableComponent : RunnableComponent { | |
7 readonly Timer m_timer; | |
8 readonly Func<Func<IPromise>, IPromise> m_dispatcher; | |
9 readonly TimeSpan m_interval; | |
10 | |
11 int m_processing; | |
12 Promise m_pending; | |
13 | |
14 protected PollingRunnableComponent(TimeSpan interval, Func<Func<IPromise>, IPromise> dispatcher, bool initialized) : base(initialized) { | |
15 m_timer = new Timer(OnInternalTick); | |
16 | |
17 m_interval = interval; | |
18 m_dispatcher = dispatcher; | |
19 } | |
20 | |
21 protected override IPromise OnStart() { | |
22 m_timer.Change(TimeSpan.Zero, m_interval); | |
23 | |
24 return base.OnStart(); | |
25 } | |
26 | |
27 void OnInternalTick(object state) { | |
28 if (StartTick()) { | |
29 try { | |
30 AwaitTick(m_dispatcher != null ? m_dispatcher(OnTick) : OnTick()); | |
31 } catch (Exception error) { | |
32 HandleTickError(error); | |
33 } | |
34 } | |
35 } | |
36 | |
37 /// <summary> | |
38 /// Starts the tick handler. | |
39 /// </summary> | |
40 /// <returns>boolean value, true - the new tick handler may be invoked, false - a tick handler is already running or a component isn't running.</returns> | |
41 /// <remarks> | |
42 /// If the component is stopping no new handlers can be run. Every successful call to this method must be completed with either AwaitTick or HandleTickError handlers. | |
43 /// </remarks> | |
44 protected virtual bool StartTick() { | |
45 if (State == ExecutionState.Running && Interlocked.CompareExchange(ref m_processing, 1, 0) == 0) { | |
46 m_pending = new Promise(); | |
47 m_pending | |
48 .On(() => m_processing = 0, PromiseEventType.All) | |
49 .On(null, LogTickError); | |
50 return true; | |
51 } | |
52 return false; | |
53 } | |
54 | |
55 protected virtual void AwaitTick(IPromise tick) { | |
56 if (tick == null) { | |
57 m_pending.Resolve(); | |
58 } else { | |
59 tick.On( | |
60 m_pending.Resolve, | |
61 m_pending.Reject, | |
62 m_pending.CancelOperation | |
63 ); | |
64 m_pending.CancellationRequested(tick.Cancel); | |
65 } | |
66 } | |
67 | |
68 protected virtual void HandleTickError(Exception error) { | |
69 m_pending.Reject(error); | |
70 } | |
71 | |
72 protected virtual void LogTickError(Exception error) { | |
73 } | |
74 | |
75 protected virtual IPromise OnTick() { | |
76 return Promise.SUCCESS; | |
77 } | |
78 | |
79 protected override IPromise OnStop() { | |
80 m_timer.Change(-1, -1); | |
81 | |
82 if (m_pending != null) { | |
83 m_pending.Cancel(); | |
84 return m_pending.Then(base.OnStop); | |
85 } | |
86 | |
87 return base.OnStop(); | |
88 } | |
89 | |
90 protected override void Dispose(bool disposing, Exception lastError) { | |
91 if (disposing) | |
92 Safe.Dispose(m_timer); | |
93 | |
94 base.Dispose(disposing, lastError); | |
95 } | |
96 } | |
97 } | |
98 |