##// END OF EJS Templates
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.

File last commit:

r196:40d7fed4a09e default
r196:40d7fed4a09e default
Show More
RunnableComponent.cs
264 lines | 8.4 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
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
r196 Action<Exception> errorOrCancel = e => {
if (e == null)
e = new OperationCanceledException();
lock (m_stateMachine) {
if (m_pending == promise) {
Move(Commands.Fail);
m_pending = null;
m_lastError = e;
}
}
throw new PromiseTransientException(e);
};
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
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
r196 },
errorOrCancel,
errorOrCancel
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
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler...
r187 // связваем текущую операцию с операцией остановки
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 }
}