##// END OF EJS Templates
Bound promise to CancellationToken...
Bound promise to CancellationToken Added new states to ExecutionSate enum. Added Safe.Guard() method to handle cleanup of the result of the promise

File last commit:

r208:7d07503621fe v2
r209:a867536c68fc v2
Show More
PollingComponent.cs
155 lines | 5.4 KiB | text/x-csharp | CSharpLexer
cin
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 using System;
using System.Threading;
using Implab.Diagnostics;
namespace Implab.Components {
public class PollingComponent : RunnableComponent {
readonly Timer m_timer;
readonly Func<Func<ICancellationToken, IPromise>, IPromise> m_dispatcher;
readonly TimeSpan m_interval;
readonly object m_lock = new object();
ActionTask m_pending;
protected PollingComponent(TimeSpan interval, Func<Func<ICancellationToken, IPromise>, IPromise> dispatcher, bool initialized) : base(initialized) {
m_timer = new Timer(OnInternalTick);
m_interval = interval;
m_dispatcher = dispatcher;
}
protected override IPromise OnStart() {
m_timer.Change(TimeSpan.Zero, m_interval);
return base.OnStart();
}
void OnInternalTick(object state) {
if (StartTick()) {
try {
if (m_dispatcher != null) {
var result = m_dispatcher(OnTick);
m_pending.CancellationRequested(result.Cancel);
AwaitTick(result);
} else {
AwaitTick(OnTick(m_pending));
}
} catch (Exception error) {
HandleTickError(error);
}
}
}
/// <summary>
/// Checks wheather there is no running handler in the component and marks that the handler is starting.
/// </summary>
/// <returns>boolean value, true - the new tick handler may be invoked, false - a tick handler is already running or a component isn't running.</returns>
/// <remarks>
/// If the component is stopping no new handlers can be run. Every successful call to this method must be completed with either AwaitTick or HandleTickError handlers.
/// </remarks>
protected virtual bool StartTick() {
lock (m_lock) {
if (State != ExecutionState.Running || m_pending != null)
return false;
// actually the component may be in a not running state here (stopping, disposed or what ever),
// but OnStop method also locks on the same object and will handle operation in m_pending
m_pending = new ActionTask(
() => {
// only one operation is running, it's safe to assing m_pending from it
m_pending = null;
},
ex => {
try {
OnTickError(ex);
// Analysis disable once EmptyGeneralCatchClause
} catch {
} finally {
m_pending = null;
}
// suppress error
},
ex => {
try {
OnTickCancel(ex);
// Analysis disable once EmptyGeneralCatchClause
} catch {
} finally {
m_pending = null;
}
// supress cancellation
},
false
);
return true;
}
}
/// <summary>
/// Awaits the tick.
/// </summary>
/// <param name="tick">Tick.</param>
/// <remarks>
/// This method is called only after StartTick method and m_pending will hold the promise which should be fulfilled.
/// </remarks>
void AwaitTick(IPromise tick) {
if (tick == null) {
m_pending.Resolve();
} else {
tick.On(
m_pending.Resolve,
m_pending.Reject,
m_pending.CancelOperation
);
}
}
/// <summary>
/// Handles the tick error.
/// </summary>
/// <remarks>
/// This method is called only after StartTick method and m_pending will hold the promise which should be fulfilled.
/// </remarks>
void HandleTickError(Exception error) {
m_pending.Reject(error);
}
protected virtual void OnTickError(Exception error) {
}
protected virtual void OnTickCancel(Exception error) {
}
/// <summary>
/// Invoked when the timer ticks, use this method to implement your logic
/// </summary>
protected virtual IPromise OnTick(ICancellationToken cancellationToken) {
cin
Added ResetState to RunnableComponent to reset in case of failure...
r205 return Promise.Success;
cin
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 }
protected override IPromise OnStop() {
m_timer.Change(-1, -1);
// the component is in the stopping state
lock (m_lock) {
// after this lock no more pending operations could be created
var pending = m_pending;
// m_pending could be fulfilled and set to null already
if (pending != null) {
pending.Cancel();
return pending.Then(base.OnStop);
}
}
return base.OnStop();
}
cin
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)...
r208 protected override void Dispose(bool disposing) {
cin
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 if (disposing)
cin
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)...
r208 m_timer.Dispose();
cin
Added 'Fail' method to RunnableComponent which allows component to move from...
r203
cin
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)...
r208 base.Dispose(disposing);
cin
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 }
}
}