Mercurial > pub > ImplabNet
annotate Implab/Components/RunnableComponent.cs @ 207:558f34b2fb50 v2
added Safe.DispatchEvent() a legacy equivalent for '?.Invoke()'
added Safe.Dispose(IEnumerable)
added PromiseExtensions.CancellationPoint to add a cancellation point to the chain of promises
added IPromise<T> PromiseExtensions.Then<T>(this IPromise<T> that, Action<T> success) overloads
added PromiseExtensions.Error() overloads to handle a error or(and) a cancellation
author | cin |
---|---|
date | Wed, 09 Nov 2016 12:03:22 +0300 |
parents | 8200ab154c8a |
children | 7d07503621fe |
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, | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
12 Reset, |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
13 Last = Reset |
184 | 14 } |
15 | |
16 class StateMachine { | |
17 static readonly ExecutionState[,] _transitions; | |
18 | |
19 static StateMachine() { | |
20 _transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1]; | |
21 | |
185 | 22 Edge(ExecutionState.Created, ExecutionState.Initializing, Commands.Init); |
23 Edge(ExecutionState.Created, ExecutionState.Disposed, Commands.Dispose); | |
24 | |
25 Edge(ExecutionState.Initializing, ExecutionState.Ready, Commands.Ok); | |
26 Edge(ExecutionState.Initializing, ExecutionState.Failed, Commands.Fail); | |
184 | 27 |
28 Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start); | |
29 Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose); | |
30 | |
31 Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok); | |
32 Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail); | |
33 Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop); | |
34 Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose); | |
35 | |
36 Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail); | |
37 Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop); | |
38 Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose); | |
39 | |
40 Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail); | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
41 Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
42 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose); |
185 | 43 |
44 Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose); | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
45 Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset); |
184 | 46 } |
47 | |
48 static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) { | |
49 _transitions[(int)s1, (int)cmd] = s2; | |
50 } | |
51 | |
52 public ExecutionState State { | |
53 get; | |
54 private set; | |
55 } | |
56 | |
57 public StateMachine(ExecutionState initial) { | |
58 State = initial; | |
59 } | |
60 | |
61 public bool Move(Commands cmd) { | |
62 var next = _transitions[(int)State, (int)cmd]; | |
63 if (next == ExecutionState.Undefined) | |
64 return false; | |
65 State = next; | |
66 return true; | |
67 } | |
68 } | |
69 | |
70 IPromise m_pending; | |
71 Exception m_lastError; | |
72 | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
73 readonly StateMachine m_stateMachine; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
74 readonly bool m_reusable; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
75 public event EventHandler<StateChangeEventArgs> StateChanged; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
76 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
77 /// <summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
78 /// Initializes component state. |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
79 /// </summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
80 /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
81 /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
82 protected RunnableComponent(bool initialized, bool reusable) { |
184 | 83 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created); |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
84 m_reusable = reusable; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
85 DisposeTimeout = 10000; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
86 } |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
87 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
88 /// <summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
89 /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop. |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
90 /// </summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
91 /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
92 protected RunnableComponent(bool initialized) : this(initialized, false) { |
184 | 93 } |
94 | |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
95 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
96 /// Gets or sets the timeout to wait for the pending operation to complete. If the pending operation doesn't finish than the component will be disposed anyway. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
97 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
98 protected int DisposeTimeout { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
99 get; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
100 set; |
185 | 101 } |
102 | |
184 | 103 void ThrowInvalidCommand(Commands cmd) { |
185 | 104 if (m_stateMachine.State == ExecutionState.Disposed) |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
105 throw new ObjectDisposedException(ToString()); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
106 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
107 throw new InvalidOperationException(String.Format("Command {0} is not allowed in the state {1}", cmd, m_stateMachine.State)); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
108 } |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
109 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
110 bool MoveIfInState(Commands cmd, IPromise pending, Exception error, ExecutionState state) { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
111 ExecutionState prev, current; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
112 lock (m_stateMachine) { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
113 if (m_stateMachine.State != state) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
114 return false; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
115 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
116 prev = m_stateMachine.State; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
117 if (!m_stateMachine.Move(cmd)) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
118 ThrowInvalidCommand(cmd); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
119 current = m_stateMachine.State; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
120 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
121 m_pending = pending; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
122 m_lastError = error; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
123 } |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
124 if (prev != current) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
125 OnStateChanged(prev, current, error); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
126 return true; |
184 | 127 } |
128 | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
129 bool MoveIfPending(Commands cmd, IPromise pending, Exception error, IPromise expected) { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
130 ExecutionState prev, current; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
131 lock (m_stateMachine) { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
132 if (m_pending != expected) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
133 return false; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
134 prev = m_stateMachine.State; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
135 if (!m_stateMachine.Move(cmd)) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
136 ThrowInvalidCommand(cmd); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
137 current = m_stateMachine.State; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
138 m_pending = pending; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
139 m_lastError = error; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
140 } |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
141 if (prev != current) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
142 OnStateChanged(prev, current, error); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
143 return true; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
144 } |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
145 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
146 IPromise Move(Commands cmd, IPromise pending, Exception error) { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
147 ExecutionState prev, current; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
148 IPromise ret; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
149 lock (m_stateMachine) { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
150 prev = m_stateMachine.State; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
151 if (!m_stateMachine.Move(cmd)) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
152 ThrowInvalidCommand(cmd); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
153 current = m_stateMachine.State; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
154 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
155 ret = m_pending; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
156 m_pending = pending; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
157 m_lastError = error; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
158 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
159 } |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
160 if(prev != current) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
161 OnStateChanged(prev, current, error); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
162 return ret; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
163 } |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
164 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
165 protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
166 var h = StateChanged; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
167 if (h != null) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
168 h(this, new StateChangeEventArgs { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
169 State = current, |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
170 LastError = error |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
171 }); |
184 | 172 } |
173 | |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
174 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
175 /// Moves the component from running to failed state. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
176 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
177 /// <param name="error">The exception which is describing the error.</param> |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
178 protected bool Fail(Exception error) { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
179 return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running); |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
180 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
181 |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
182 /// <summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
183 /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>. |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
184 /// </summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
185 /// <returns>True if component is reset to <see cref="ExecutionState.Ready"/>, false if the componet wasn't |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
186 /// in <see cref="ExecutionState.Failed"/> state.</returns> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
187 /// <remarks> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
188 /// This method checks the current state of the component and if it's in <see cref="ExecutionState.Failed"/> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
189 /// moves component to <see cref="ExecutionState.Initializing"/>. |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
190 /// The <see cref="OnResetState()"/> is called and if this method completes succesfully the component moved |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
191 /// to <see cref="ExecutionState.Ready"/> state, otherwise the component is moved to <see cref="ExecutionState.Failed"/> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
192 /// state. If <see cref="OnResetState()"/> throws an exception it will be propagated by this method to the caller. |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
193 /// </remarks> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
194 protected bool ResetState() { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
195 if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed)) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
196 return false; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
197 |
184 | 198 try { |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
199 OnResetState(); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
200 Move(Commands.Ok, null, null); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
201 return true; |
184 | 202 } catch (Exception err) { |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
203 Move(Commands.Fail, null, err); |
184 | 204 throw; |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
205 } |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
206 } |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
207 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
208 /// <summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
209 /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state. |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
210 /// </summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
211 /// <remarks> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
212 /// Default implementation throws <see cref="NotImplementedException"/> which will cause the component |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
213 /// fail to reset it's state and it left in <see cref="ExecutionState.Failed"/> state. |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
214 /// If this method doesn't throw exceptions the component is moved to <see cref="ExecutionState.Ready"/> state. |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
215 /// </remarks> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
216 protected virtual void OnResetState() { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
217 throw new NotImplementedException(); |
184 | 218 } |
219 | |
185 | 220 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) { |
221 IPromise promise = null; | |
222 IPromise prev; | |
184 | 223 |
185 | 224 var task = new ActionChainTask(action, null, null, true); |
225 | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
226 Action<Exception> errorOrCancel = e => { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
227 if (e == null) |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
228 e = new OperationCanceledException(); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
229 MoveIfPending(Commands.Fail, null, e, promise); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
230 throw new PromiseTransientException(e); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
231 }; |
184 | 232 |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
233 promise = task.Then( |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
234 () => MoveIfPending(Commands.Ok, null, null, promise), |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
235 errorOrCancel, |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
236 errorOrCancel |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
237 ); |
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
|
238 |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
239 prev = Move(cmd, promise, null); |
157 | 240 |
185 | 241 if (prev == null) |
242 task.Resolve(); | |
243 else | |
244 chain(prev, task); | |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
245 |
185 | 246 return promise; |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
247 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
248 |
184 | 249 |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
250 #region IInitializable implementation |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
251 |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
252 public void Initialize() { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
253 Move(Commands.Init, null, null); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
254 |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
255 try { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
256 OnInitialize(); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
257 Move(Commands.Ok, null, null); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
258 } catch (Exception err) { |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
259 Move(Commands.Fail, null, err); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
260 throw; |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
261 } |
184 | 262 } |
263 | |
264 protected virtual void OnInitialize() { | |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
265 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
266 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
267 #endregion |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
268 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
269 #region IRunnable implementation |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
270 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
271 public IPromise Start() { |
185 | 272 return InvokeAsync(Commands.Start, OnStart, null); |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
273 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
274 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
275 protected virtual IPromise OnStart() { |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
276 return Promise.Success; |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
277 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
278 |
185 | 279 public IPromise Stop() { |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
280 var pending = InvokeAsync(Commands.Stop, OnStop, StopPending); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
281 return m_reusable ? pending : pending.Then(Dispose); |
185 | 282 } |
283 | |
284 protected virtual IPromise OnStop() { | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
285 return Promise.Success; |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
286 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
287 |
185 | 288 /// <summary> |
289 /// Stops the current operation if one exists. | |
290 /// </summary> | |
291 /// <param name="current">Current.</param> | |
292 /// <param name="stop">Stop.</param> | |
293 protected virtual void StopPending(IPromise current, IDeferred stop) { | |
294 if (current == null) { | |
295 stop.Resolve(); | |
296 } 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
|
297 // связваем текущую операцию с операцией остановки |
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
|
298 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
|
299 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
|
300 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
|
301 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
|
302 ); |
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
|
303 // посылаем текущей операции сигнал остановки |
185 | 304 current.Cancel(); |
305 } | |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
306 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
307 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
308 public ExecutionState State { |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
309 get { |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
310 return m_stateMachine.State; |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
311 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
312 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
313 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
314 public Exception LastError { |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
315 get { |
185 | 316 return m_lastError; |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
317 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
318 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
319 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
320 #endregion |
185 | 321 |
322 #region IDisposable implementation | |
323 | |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
324 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
325 /// Releases all resource used by the <see cref="Implab.Components.RunnableComponent"/> object. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
326 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
327 /// <remarks> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
328 /// <para>Will not try to stop the component, it will just release all resources. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
329 /// To cleanup the component gracefully use <see cref="Stop()"/> method.</para> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
330 /// <para> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
331 /// In normal cases the <see cref="Dispose()"/> method shouldn't be called, the call to the <see cref="Stop()"/> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
332 /// method is sufficient to cleanup the component. Call <see cref="Dispose()"/> only to cleanup after errors, |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
333 /// especially if <see cref="Stop"/> method is failed. Using this method insted of <see cref="Stop()"/> may |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
334 /// lead to the data loss by the component. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
335 /// </para></remarks> |
185 | 336 public void Dispose() { |
337 IPromise pending; | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
338 |
185 | 339 lock (m_stateMachine) { |
340 if (m_stateMachine.State == ExecutionState.Disposed) | |
341 return; | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
342 pending = Move(Commands.Dispose, null, null); |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
343 } |
185 | 344 |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
345 GC.SuppressFinalize(this); |
185 | 346 if (pending != null) { |
347 pending.Cancel(); | |
348 pending.Timeout(DisposeTimeout).On( | |
349 () => Dispose(true, null), | |
350 err => Dispose(true, err), | |
351 reason => Dispose(true, new OperationCanceledException("The operation is cancelled", reason)) | |
352 ); | |
353 } else { | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
354 Dispose(true, null); |
185 | 355 } |
356 } | |
357 | |
358 ~RunnableComponent() { | |
359 Dispose(false, null); | |
360 } | |
361 | |
362 #endregion | |
363 | |
205
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
364 /// <summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
365 /// Releases all resources used by the component, called automatically, override this method to implement your cleanup. |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
366 /// </summary> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
367 /// <param name="disposing">true if this method is called during normal dispose process.</param> |
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
cin
parents:
203
diff
changeset
|
368 /// <param name="lastError">The last error which occured during the component stop.</param> |
185 | 369 protected virtual void Dispose(bool disposing, Exception lastError) { |
370 | |
371 } | |
372 | |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
373 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
374 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
375 |