Mercurial > pub > ImplabNet
view Implab/Components/PollingComponent.cs @ 259:7d52dc684bbd v3
PollingComponent: implemented correct stopping
author | cin |
---|---|
date | Fri, 13 Apr 2018 03:57:39 +0300 |
parents | d0876436d95d |
children | 547a2fc0d93e |
line wrap: on
line source
using System; using System.Threading; using System.Threading.Tasks; namespace Implab.Components { public abstract class PollingComponent : RunnableComponent { readonly Timer m_timer; readonly CancellationTokenSource m_cancellation = new CancellationTokenSource(); Task m_pending; Task m_poll; /// <summary> /// Poll interval in milliseconds. /// </summary> /// <returns></returns> public int Interval { get; set; } /// <summary> /// Delay to the first poll after start in milliseconds /// </summary> /// <returns></returns> public int Delay { get; set; } /// <summary> /// Indicates how to handle unhandled exceptions in <see cref="Poll()"/> method. /// </summary> /// <returns></returns> public bool FailOnError { get; set; } /// <summary> /// Event for the unhandled exceptions in <see cref="Poll()"/> method. /// </summary> public event EventHandler<UnhandledExceptionEventArgs> UnhandledException; protected PollingComponent(bool initialized) : base(initialized) { m_timer = new Timer(OnTimer); } protected override void RunInternal() { ScheduleNextPoll(Delay); } protected override async Task StopInternalAsync(CancellationToken ct) { // component in Stopping state, no new polls will be scheduled m_cancellation.Cancel(); try { // await for pending poll await m_poll; } catch (OperationCanceledException e) { // OK } } protected abstract Task Poll(CancellationToken ct); void ScheduleNextPoll(int timeout) { lock (SynchronizationObject) { if (State == ExecutionState.Running) { m_pending = Safe.CreateTask(m_cancellation.Token); m_poll = m_pending.Then(() => Poll(m_cancellation.Token)); m_timer.Change(timeout, Timeout.Infinite); } } } async void OnTimer(object state) { try { m_pending.Start(); await m_poll; } catch (Exception e) { UnhandledException.DispatchEvent(this, new UnhandledExceptionEventArgs(e, false)); if (FailOnError) Fail(e); } ScheduleNextPoll(Interval); } protected override void Dispose(bool disposing) { if (disposing) Safe.Dispose(m_timer, m_cancellation); base.Dispose(disposing); } } }