Mercurial > pub > ImplabNet
annotate Implab/Components/RunnableComponent.cs @ 223:27ea7f07e2e4 default
Слияние
| author | cin |
|---|---|
| date | Tue, 22 Aug 2017 09:35:54 +0300 |
| parents | 40d7fed4a09e |
| children | 2651cb9a4250 |
| rev | line source |
|---|---|
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
1 using System; |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
2 |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
3 namespace Implab.Components { |
| 185 | 4 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable { |
| 184 | 5 enum Commands { |
| 6 Ok = 0, | |
| 7 Fail, | |
| 8 Init, | |
| 9 Start, | |
| 10 Stop, | |
| 11 Dispose, | |
| 12 Last = Dispose | |
| 13 } | |
| 14 | |
| 15 class StateMachine { | |
| 16 static readonly ExecutionState[,] _transitions; | |
| 17 | |
| 18 static StateMachine() { | |
| 19 _transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1]; | |
| 20 | |
| 185 | 21 Edge(ExecutionState.Created, ExecutionState.Initializing, Commands.Init); |
| 22 Edge(ExecutionState.Created, ExecutionState.Disposed, Commands.Dispose); | |
| 23 | |
| 24 Edge(ExecutionState.Initializing, ExecutionState.Ready, Commands.Ok); | |
| 25 Edge(ExecutionState.Initializing, ExecutionState.Failed, Commands.Fail); | |
| 184 | 26 |
| 27 Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start); | |
| 28 Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose); | |
| 29 | |
| 30 Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok); | |
| 31 Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail); | |
| 32 Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop); | |
| 33 Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose); | |
| 34 | |
| 35 Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail); | |
| 36 Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop); | |
| 37 Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose); | |
| 38 | |
| 39 Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail); | |
| 40 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok); | |
| 185 | 41 |
| 42 Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose); | |
| 184 | 43 } |
| 44 | |
| 45 static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) { | |
| 46 _transitions[(int)s1, (int)cmd] = s2; | |
| 47 } | |
| 48 | |
| 49 public ExecutionState State { | |
| 50 get; | |
| 51 private set; | |
| 52 } | |
| 53 | |
| 54 public StateMachine(ExecutionState initial) { | |
| 55 State = initial; | |
| 56 } | |
| 57 | |
| 58 public bool Move(Commands cmd) { | |
| 59 var next = _transitions[(int)State, (int)cmd]; | |
| 60 if (next == ExecutionState.Undefined) | |
| 61 return false; | |
| 62 State = next; | |
| 63 return true; | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 IPromise m_pending; | |
| 68 Exception m_lastError; | |
| 69 | |
| 70 readonly StateMachine m_stateMachine; | |
| 71 | |
| 72 protected RunnableComponent(bool initialized) { | |
| 73 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created); | |
| 74 } | |
| 75 | |
| 185 | 76 protected virtual int DisposeTimeout { |
| 77 get { | |
| 78 return 10000; | |
| 79 } | |
| 80 } | |
| 81 | |
| 184 | 82 void ThrowInvalidCommand(Commands cmd) { |
| 185 | 83 if (m_stateMachine.State == ExecutionState.Disposed) |
| 84 throw new ObjectDisposedException(ToString()); | |
| 85 | |
| 184 | 86 throw new InvalidOperationException(String.Format("Commnd {0} is not allowed in the state {1}", cmd, m_stateMachine.State)); |
| 87 } | |
| 88 | |
| 185 | 89 void Move(Commands cmd) { |
| 90 if (!m_stateMachine.Move(cmd)) | |
| 91 ThrowInvalidCommand(cmd); | |
| 184 | 92 } |
| 93 | |
| 185 | 94 void Invoke(Commands cmd, Action action) { |
| 95 lock (m_stateMachine) | |
| 96 Move(cmd); | |
| 97 | |
| 184 | 98 try { |
| 99 action(); | |
| 185 | 100 lock(m_stateMachine) |
| 101 Move(Commands.Ok); | |
| 102 | |
| 184 | 103 } catch (Exception err) { |
| 185 | 104 lock (m_stateMachine) { |
| 105 Move(Commands.Fail); | |
| 106 m_lastError = err; | |
| 107 } | |
| 184 | 108 throw; |
| 109 } | |
| 110 } | |
| 111 | |
| 185 | 112 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) { |
| 113 IPromise promise = null; | |
| 114 IPromise prev; | |
| 184 | 115 |
| 185 | 116 var task = new ActionChainTask(action, null, null, true); |
| 117 | |
| 118 lock (m_stateMachine) { | |
| 119 Move(cmd); | |
| 120 | |
| 121 prev = m_pending; | |
| 184 | 122 |
|
196
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
123 Action<Exception> errorOrCancel = e => { |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
124 if (e == null) |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
125 e = new OperationCanceledException(); |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
126 |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
127 lock (m_stateMachine) { |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
128 if (m_pending == promise) { |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
129 Move(Commands.Fail); |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
130 m_pending = null; |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
131 m_lastError = e; |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
132 } |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
133 } |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
134 throw new PromiseTransientException(e); |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
135 }; |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
136 |
| 185 | 137 promise = task.Then( |
| 138 () => { | |
| 139 lock(m_stateMachine) { | |
| 140 if (m_pending == promise) { | |
| 141 Move(Commands.Ok); | |
| 142 m_pending = null; | |
| 143 } | |
| 184 | 144 } |
|
196
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
145 }, |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
146 errorOrCancel, |
|
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
147 errorOrCancel |
| 185 | 148 ); |
| 157 | 149 |
| 185 | 150 m_pending = promise; |
| 151 } | |
| 157 | 152 |
| 185 | 153 if (prev == null) |
| 154 task.Resolve(); | |
| 155 else | |
| 156 chain(prev, task); | |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
157 |
| 185 | 158 return promise; |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
159 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
160 |
| 184 | 161 |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
162 #region IInitializable implementation |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
163 |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
164 public void Init() { |
| 184 | 165 Invoke(Commands.Init, OnInitialize); |
| 166 } | |
| 167 | |
| 168 protected virtual void OnInitialize() { | |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
169 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
170 |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
171 #endregion |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
172 |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
173 #region IRunnable implementation |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
174 |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
175 public IPromise Start() { |
| 185 | 176 return InvokeAsync(Commands.Start, OnStart, null); |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
177 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
178 |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
179 protected virtual IPromise OnStart() { |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
180 return Promise.SUCCESS; |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
181 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
182 |
| 185 | 183 public IPromise Stop() { |
| 184 return InvokeAsync(Commands.Stop, OnStop, StopPending).Then(Dispose); | |
| 185 } | |
| 186 | |
| 187 protected virtual IPromise OnStop() { | |
| 188 return Promise.SUCCESS; | |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
189 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
190 |
| 185 | 191 /// <summary> |
| 192 /// Stops the current operation if one exists. | |
| 193 /// </summary> | |
| 194 /// <param name="current">Current.</param> | |
| 195 /// <param name="stop">Stop.</param> | |
| 196 protected virtual void StopPending(IPromise current, IDeferred stop) { | |
| 197 if (current == null) { | |
| 198 stop.Resolve(); | |
| 199 } else { | |
|
187
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
200 // связваем текущую операцию с операцией остановки |
|
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
201 current.On( |
|
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
202 stop.Resolve, // если текущая операция заверщилась, то можно начинать остановку |
|
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
203 stop.Reject, // если текущая операция дала ошибку - то все плохо, нельзя продолжать |
|
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
204 e => stop.Resolve() // если текущая отменилась, то можно начинать остановку |
|
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
205 ); |
|
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
206 // посылаем текущей операции сигнал остановки |
| 185 | 207 current.Cancel(); |
| 208 } | |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
209 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
210 |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
211 public ExecutionState State { |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
212 get { |
| 185 | 213 return m_stateMachine.State; |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
214 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
215 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
216 |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
217 public Exception LastError { |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
218 get { |
| 185 | 219 return m_lastError; |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
220 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
221 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
222 |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
223 #endregion |
| 185 | 224 |
| 225 #region IDisposable implementation | |
| 226 | |
| 227 public void Dispose() { | |
| 228 IPromise pending; | |
| 229 lock (m_stateMachine) { | |
| 230 if (m_stateMachine.State == ExecutionState.Disposed) | |
| 231 return; | |
| 232 | |
| 233 Move(Commands.Dispose); | |
| 234 | |
| 235 GC.SuppressFinalize(this); | |
| 236 | |
| 237 pending = m_pending; | |
| 238 m_pending = null; | |
| 239 } | |
| 240 if (pending != null) { | |
| 241 pending.Cancel(); | |
| 242 pending.Timeout(DisposeTimeout).On( | |
| 243 () => Dispose(true, null), | |
| 244 err => Dispose(true, err), | |
| 245 reason => Dispose(true, new OperationCanceledException("The operation is cancelled", reason)) | |
| 246 ); | |
| 247 } else { | |
| 248 Dispose(true, m_lastError); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 ~RunnableComponent() { | |
| 253 Dispose(false, null); | |
| 254 } | |
| 255 | |
| 256 #endregion | |
| 257 | |
| 258 protected virtual void Dispose(bool disposing, Exception lastError) { | |
| 259 | |
| 260 } | |
| 261 | |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
262 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
263 } |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
264 |
