Mercurial > pub > ImplabNet
view Implab/Components/PollingRunnableComponent.cs @ 202:2651cb9a4250 v2
Implemented PollingRunnableComponent
author | cin |
---|---|
date | Tue, 18 Oct 2016 01:03:49 +0300 |
parents | |
children |
line wrap: on
line source
using System; using System.Threading; using Implab.Diagnostics; namespace Implab.Components { public class PollingRunnableComponent : RunnableComponent { readonly Timer m_timer; readonly Func<Func<IPromise>, IPromise> m_dispatcher; readonly TimeSpan m_interval; int m_processing; Promise m_pending; protected PollingRunnableComponent(TimeSpan interval, Func<Func<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 { AwaitTick(m_dispatcher != null ? m_dispatcher(OnTick) : OnTick()); } catch (Exception error) { HandleTickError(error); } } } /// <summary> /// Starts the tick handler. /// </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() { if (State == ExecutionState.Running && Interlocked.CompareExchange(ref m_processing, 1, 0) == 0) { m_pending = new Promise(); m_pending .On(() => m_processing = 0, PromiseEventType.All) .On(null, LogTickError); return true; } return false; } protected virtual void AwaitTick(IPromise tick) { if (tick == null) { m_pending.Resolve(); } else { tick.On( m_pending.Resolve, m_pending.Reject, m_pending.CancelOperation ); m_pending.CancellationRequested(tick.Cancel); } } protected virtual void HandleTickError(Exception error) { m_pending.Reject(error); } protected virtual void LogTickError(Exception error) { } protected virtual IPromise OnTick() { return Promise.SUCCESS; } protected override IPromise OnStop() { m_timer.Change(-1, -1); if (m_pending != null) { m_pending.Cancel(); return m_pending.Then(base.OnStop); } return base.OnStop(); } protected override void Dispose(bool disposing, Exception lastError) { if (disposing) Safe.Dispose(m_timer); base.Dispose(disposing, lastError); } } }