##// END OF EJS Templates
Fixed broken Implab.Diagnostics.Interactive
Fixed broken Implab.Diagnostics.Interactive

File last commit:

r203:4d9830a9bbb8 v2
r204:cbb0bd8fc0d1 v2
Show More
RunnableComponent.cs
296 lines | 10.1 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
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 DisposeTimeout = 10000;
cin
working on runnable component
r184 }
cin
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 /// <summary>
/// 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.
/// </summary>
protected int DisposeTimeout {
get;
set;
cin
runnable component, work in progress
r185 }
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
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 /// <summary>
/// Moves the component from running to failed state.
/// </summary>
/// <param name="error">The exception which is describing the error.</param>
/// <returns>Returns true if the component is set to the failed state, false - otherwise.
/// This method works only for the running state, in any other state it will return false.</returns>
protected bool Fail(Exception error) {
lock (m_stateMachine) {
if(m_stateMachine.State == ExecutionState.Running) {
m_stateMachine.Move(Commands.Fail);
m_lastError = error;
return true;
}
}
return false;
}
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
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 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
cin
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 /// <summary>
/// Releases all resource used by the <see cref="Implab.Components.RunnableComponent"/> object.
/// </summary>
/// <remarks>
/// <para>Will not try to stop the component, it will just release all resources.
/// To cleanup the component gracefully use <see cref="Stop()"/> method.</para>
/// <para>
/// In normal cases the <see cref="Dispose()"/> method shouldn't be called, the call to the <see cref="Stop()"/>
/// method is sufficient to cleanup the component. Call <see cref="Dispose()"/> only to cleanup after errors,
/// especially if <see cref="Stop"/> method is failed. Using this method insted of <see cref="Stop()"/> may
/// lead to the data loss by the component.
/// </para></remarks>
cin
runnable component, work in progress
r185 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 }
}