##// END OF EJS Templates
working on cancelation and error handling
working on cancelation and error handling

File last commit:

r186:75103928da09 ref20160224
r186:75103928da09 ref20160224
Show More
RunnableComponent.cs
255 lines | 7.8 KiB | text/x-csharp | CSharpLexer
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 using System;
namespace Implab.Components {
cin
runnable component, work in progress
r185 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable {
cin
working on runnable component
r184 enum Commands {
Ok = 0,
Fail,
Init,
Start,
Stop,
Dispose,
Last = Dispose
}
class StateMachine {
static readonly ExecutionState[,] _transitions;
static StateMachine() {
_transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
cin
runnable component, work in progress
r185 Edge(ExecutionState.Created, ExecutionState.Initializing, Commands.Init);
Edge(ExecutionState.Created, ExecutionState.Disposed, Commands.Dispose);
Edge(ExecutionState.Initializing, ExecutionState.Ready, Commands.Ok);
Edge(ExecutionState.Initializing, ExecutionState.Failed, Commands.Fail);
cin
working on runnable component
r184
Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start);
Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose);
Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok);
Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail);
Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop);
Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose);
Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail);
Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop);
Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose);
Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail);
Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
cin
runnable component, work in progress
r185
Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose);
cin
working on runnable component
r184 }
static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
_transitions[(int)s1, (int)cmd] = s2;
}
public ExecutionState State {
get;
private set;
}
public StateMachine(ExecutionState initial) {
State = initial;
}
public bool Move(Commands cmd) {
var next = _transitions[(int)State, (int)cmd];
if (next == ExecutionState.Undefined)
return false;
State = next;
return true;
}
}
IPromise m_pending;
Exception m_lastError;
readonly StateMachine m_stateMachine;
protected RunnableComponent(bool initialized) {
m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created);
}
cin
runnable component, work in progress
r185 protected virtual int DisposeTimeout {
get {
return 10000;
}
}
cin
working on runnable component
r184 void ThrowInvalidCommand(Commands cmd) {
cin
runnable component, work in progress
r185 if (m_stateMachine.State == ExecutionState.Disposed)
throw new ObjectDisposedException(ToString());
cin
working on runnable component
r184 throw new InvalidOperationException(String.Format("Commnd {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
}
cin
runnable component, work in progress
r185 void Move(Commands cmd) {
if (!m_stateMachine.Move(cmd))
ThrowInvalidCommand(cmd);
cin
working on runnable component
r184 }
cin
runnable component, work in progress
r185 void Invoke(Commands cmd, Action action) {
lock (m_stateMachine)
Move(cmd);
cin
working on runnable component
r184 try {
action();
cin
runnable component, work in progress
r185 lock(m_stateMachine)
Move(Commands.Ok);
cin
working on runnable component
r184 } catch (Exception err) {
cin
runnable component, work in progress
r185 lock (m_stateMachine) {
Move(Commands.Fail);
m_lastError = err;
}
cin
working on runnable component
r184 throw;
}
}
cin
runnable component, work in progress
r185 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) {
IPromise promise = null;
IPromise prev;
cin
working on runnable component
r184
cin
runnable component, work in progress
r185 var task = new ActionChainTask(action, null, null, true);
lock (m_stateMachine) {
Move(cmd);
prev = m_pending;
cin
working on runnable component
r184
cin
runnable component, work in progress
r185 promise = task.Then(
() => {
lock(m_stateMachine) {
if (m_pending == promise) {
Move(Commands.Ok);
m_pending = null;
}
cin
working on runnable component
r184 }
cin
runnable component, work in progress
r185 }, e => {
lock(m_stateMachine) {
if (m_pending == promise) {
Move(Commands.Fail);
m_pending = null;
m_lastError = e;
}
}
throw new PromiseTransientException(e);
},
r => {
cin
working on cancelation and error handling
r186 // handle cancellation as exception
cin
runnable component, work in progress
r185 throw new OperationCanceledException("The operation has been cancelled", r);
cin
working on runnable component
r184 }
cin
runnable component, work in progress
r185 );
cin
sync
r157
cin
runnable component, work in progress
r185 m_pending = promise;
}
cin
sync
r157
cin
runnable component, work in progress
r185 if (prev == null)
task.Resolve();
else
chain(prev, task);
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156
cin
runnable component, work in progress
r185 return promise;
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 }
cin
working on runnable component
r184
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 #region IInitializable implementation
public void Init() {
cin
working on runnable component
r184 Invoke(Commands.Init, OnInitialize);
}
protected virtual void OnInitialize() {
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 }
#endregion
#region IRunnable implementation
public IPromise Start() {
cin
runnable component, work in progress
r185 return InvokeAsync(Commands.Start, OnStart, null);
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 }
protected virtual IPromise OnStart() {
return Promise.SUCCESS;
}
cin
runnable component, work in progress
r185 public IPromise Stop() {
return InvokeAsync(Commands.Stop, OnStop, StopPending).Then(Dispose);
}
protected virtual IPromise OnStop() {
return Promise.SUCCESS;
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 }
cin
runnable component, work in progress
r185 /// <summary>
/// Stops the current operation if one exists.
/// </summary>
/// <param name="current">Current.</param>
/// <param name="stop">Stop.</param>
protected virtual void StopPending(IPromise current, IDeferred stop) {
if (current == null) {
stop.Resolve();
} else {
cin
working on cancelation and error handling
r186 current.On(stop.Resolve, stop.Reject, e => stop.Resolve());
cin
runnable component, work in progress
r185 current.Cancel();
}
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 }
public ExecutionState State {
get {
cin
runnable component, work in progress
r185 return m_stateMachine.State;
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 }
}
public Exception LastError {
get {
cin
runnable component, work in progress
r185 return m_lastError;
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 }
}
#endregion
cin
runnable component, work in progress
r185
#region IDisposable implementation
public void Dispose() {
IPromise pending;
lock (m_stateMachine) {
if (m_stateMachine.State == ExecutionState.Disposed)
return;
Move(Commands.Dispose);
GC.SuppressFinalize(this);
pending = m_pending;
m_pending = null;
}
if (pending != null) {
pending.Cancel();
pending.Timeout(DisposeTimeout).On(
() => Dispose(true, null),
err => Dispose(true, err),
reason => Dispose(true, new OperationCanceledException("The operation is cancelled", reason))
);
} else {
Dispose(true, m_lastError);
}
}
~RunnableComponent() {
Dispose(false, null);
}
#endregion
protected virtual void Dispose(bool disposing, Exception lastError) {
}
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 }
}