Feedback

C# - Wiederkehrende Tasks

Veröffentlicht von am 11/9/2015
(2 Bewertungen)
Basisklasse für die Implementierung von wiederkehrenden Tasks während der Programm Ausführung.
Hierbei wird auf Threads, BackgroundWorker und Timer Objekte verzichtet.

Beispiel Program:
namespace Snippets.Net
{
using System;
using System.Collections.Generic;

class ExampleProgram
{
static void Main(string[] args)
{
var jobs = new List<ISchedulerJob>();
jobs.Add(new SchedulerJobA());
jobs.Add(new SchedulerJobB());

jobs.ForEach(x => x.Start());

Console.ReadLine();

jobs.ForEach(x => x.Stop());
}
}

public class SchedulerJobA : SchedulerJobBase
{
protected override void OnDispose()
{
}

protected override void OnExecution()
{
WriteToConsole($"{ GetType().Name} Warning");
}

protected override void OnInstanceCreated()
{
Delay = TimeSpan.FromSeconds(8);
Interval = TimeSpan.FromSeconds(16);
}
}

public class SchedulerJobB : SchedulerJobBase
{
protected override void OnDispose()
{
}

protected override void OnExecution()
{
WriteToConsole($"{GetType().Name} Information");
}

protected override void OnInstanceCreated()
{
Delay = TimeSpan.FromSeconds(5);
Interval = TimeSpan.FromSeconds(3);
}
}
}


Beispiel Ausgabe:
[13:50:18] Scheduler Job 'SchedulerJobA' started. Recurring every 16 seconds, after a delay of 00:00:07.9927205.
[13:50:18] Scheduler Job 'SchedulerJobB' started. Recurring every 03 seconds, after a delay of 00:00:04.9834796.
[13:50:23] SchedulerJobB - Calling OnExecution Method
[13:50:23] SchedulerJobB Information
[13:50:26] SchedulerJobB - Calling OnExecution Method
[13:50:26] SchedulerJobA - Calling OnExecution Method
[13:50:26] SchedulerJobB Information
[13:50:26] SchedulerJobA Warning
[13:50:29] SchedulerJobB - Calling OnExecution Method
[13:50:29] SchedulerJobB Information
[13:50:32] SchedulerJobB - Calling OnExecution Method
[13:50:32] SchedulerJobB Information
[13:50:35] SchedulerJobB - Calling OnExecution Method
[13:50:35] SchedulerJobB Information
[13:50:38] SchedulerJobB - Calling OnExecution Method
[13:50:38] SchedulerJobB Information
[13:50:41] SchedulerJobB - Calling OnExecution Method
[13:50:41] SchedulerJobB Information
[13:50:42] SchedulerJobA - Calling OnExecution Method
[13:50:42] SchedulerJobA Warning
[13:50:44] SchedulerJobB - Calling OnExecution Method
[13:50:44] SchedulerJobB Information
[13:50:47] SchedulerJobB - Calling OnExecution Method
[13:50:47] SchedulerJobB Information
namespace Snippets.Net
{
    using System;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;

    public interface ISchedulerJob : IDisposable
    {
        CancellationTokenSource CancellationTokenSource { get; }

        TimeSpan? Delay { get; set; }
        DateTime? EndTime { get; set; }
        TimeSpan Interval { get; set; }
        DateTime? StartTime { get; set; }

        bool IsActive { get; }

        void Start();
        void Stop();
    }

    public abstract class SchedulerJobBase : ISchedulerJob
    {
        #region Fields
        private bool _disposed = false;

        private CancellationTokenSource _tokenSource;

        private DateTime? _startTime;
        private DateTime? _endTime;

        private bool _isActive;
        private TimeSpan _interval;

        private readonly Stopwatch _stopWatch;
        #endregion

        #region Properties
        public CancellationTokenSource CancellationTokenSource => _tokenSource;

        public TimeSpan? Delay
        {
            get
            {
                if (!_startTime.HasValue) return null;
                return _startTime.Value - DateTime.Now;
            }

            set
            {
                if (value.HasValue) _startTime = DateTime.Now.Add(value.Value);
            }
        }

        public DateTime? EndTime
        {
            get
            {
                return _endTime;
            }

            set
            {
                _endTime = value;
            }
        }

        public TimeSpan Interval
        {
            get
            {
                return _interval;
            }

            set
            {
                _interval = value;
            }
        }

        public bool IsActive => _isActive;

        public DateTime? StartTime
        {
            get
            {
                return _startTime;
            }

            set
            {
                _startTime = value;
            }
        }
        #endregion

        #region Constructor
        protected SchedulerJobBase() : base()
        {
            OnInstanceCreated();

            _tokenSource = new CancellationTokenSource();
            _isActive = false;
            _stopWatch = new Stopwatch();
        }
        #endregion

        #region Methods
        public async void Start()
        {
            if (_isActive) return;

            WriteToConsole($"Scheduler Job '{GetType().Name}' started. Recurring every {Interval:ss} seconds, after a delay of {Delay}.");
            _isActive = true;
            var currentDelay = TimeSpan.Zero;
            if (_startTime.HasValue) currentDelay = _startTime.Value - DateTime.Now;
            if (currentDelay <= TimeSpan.Zero) currentDelay = TimeSpan.Zero;

            await Task.Delay(currentDelay, _tokenSource.Token);

            TimeSpan newInterval;

            while ((!_tokenSource.IsCancellationRequested))
            {
                _stopWatch.Restart();
                try
                {
                    WriteToConsole($"{GetType().Name} - Calling OnExecution Method");
                    await Task.Run(new Action(OnExecution), _tokenSource.Token);
                }
                catch (Exception ex)
                {
                    WriteToConsole($"Error - {GetType().Name}");
                    WriteToConsole(ex.ToString());
                }
                finally
                {
                    _stopWatch.Stop();
                }

                newInterval = _interval - _stopWatch.Elapsed;
                if (newInterval < TimeSpan.Zero) newInterval = _interval;

                if (_endTime.HasValue && _endTime.Value < DateTime.Now) Stop();
                await Task.Delay(newInterval, _tokenSource.Token);
            }
        }

        public void Stop()
        {
            if (!_isActive) return;
            Console.WriteLine($"{GetType().Name} stopped");
            _tokenSource.Cancel();
            _isActive = false;
        }

        protected abstract void OnInstanceCreated();

        protected abstract void OnExecution();

        protected abstract void OnDispose();

        protected void WriteToConsole(string message)
        {
            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] " + message);
        }
        #endregion

        #region IDisposable Support
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _tokenSource?.Dispose();
                    OnDispose();
                }
                _disposed = true;
            }
        }

        void IDisposable.Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}

Kommentare zum Snippet

 

Logge dich ein, um hier zu kommentieren!