Best way to do a task looping in Windows Service

前端 未结 2 1410
清歌不尽
清歌不尽 2020-12-08 08:26

I have a method that send some SMS to our customers that look like below:

public void ProccessSmsQueue()
{
   SmsDbContext context = new SmsDbContext();
   I         


        
相关标签:
2条回答
  • 2020-12-08 08:47

    Sample Worker Class that I have used in Windows Services. It supports stopping in a 'clean' way by using a lock. You just have to add your code in DoWork, set your timer in the StartTimerAndWork method (in milliseconds), and use this class in your service.

    public class TempWorker
        {
            private System.Timers.Timer _timer = new System.Timers.Timer();
            private Thread _thread = null;
    
            private object _workerStopRequestedLock = new object();
            private bool _workerStopRequested = false;
    
            private object _loopInProgressLock = new object();
            private bool _loopInProgress = false;
    
            bool LoopInProgress
            {
                get
                {
                    bool rez = true;
    
                    lock (_loopInProgressLock)
                        rez = _loopInProgress;
    
                    return rez;
                }
                set
                {
                    lock (_loopInProgressLock)
                        _loopInProgress = value;
                }
            }
    
            #region constructors
            public TempWorker()
            {
            }
            #endregion
    
            #region public methods
            public void StartWorker()
            {
                lock (_workerStopRequestedLock)
                {
                    this._workerStopRequested = false;
                }
                _thread = new Thread(new ThreadStart(StartTimerAndWork));
                _thread.Start();
            }
            public void StopWorker()
            {
                if (this._thread == null)
                    return;
    
                lock (_workerStopRequestedLock)
                    this._workerStopRequested = true;
    
                int iter = 0;
                while (LoopInProgress)
                {
                    Thread.Sleep(100);
    
                    iter++;
    
                    if (iter == 60)
                    {
                        _thread.Abort();
                    }
                }
    
                //if (!_thread.Join(60000))
                //    _thread.Abort();
    
            }
            #endregion
    
    
            #region private methods
    
            private void StartTimerAndWork()
            {
                this._timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
                this._timer.Interval = 10000;//milliseconds
                this._timer.Enabled = true;
                this._timer.Start();
    
            }
    
    
            #endregion
    
    
            #region event handlers
            private void timer_Elapsed(object sender, ElapsedEventArgs e)
            {
                if (!LoopInProgress)
                {
                    lock (_workerStopRequestedLock)
                    {
                        if (this._workerStopRequested)
                        {
                            this._timer.Stop();
                            return;
                        }
                    }
    
                    DoWork();
    
                }
            }
    
            private void DoWork()
            {
                try
                {
                    this.LoopInProgress = true;
    
                    //DO WORK HERE
    
                }
                catch (Exception ex)
                {
                    //LOG EXCEPTION HERE
                }
                finally
                {
                    this.LoopInProgress = false;
                }
            }
            #endregion
    
        }
    
    0 讨论(0)
  • 2020-12-08 08:51

    You should have an async method that accepts a CancellationToken so it knows when to stop, calls ProccessSmsQueue in a try-catch block and uses Task.Delay to asynchronously wait until the next time it needs to run:

    public async Task DoWorkAsync(CancellationToken token)
    {
        while (true)
        {
            try
            {
                ProccessSmsQueue();
            }
            catch (Exception e)
            {
                // Handle exception
            }
            await Task.Delay(TimeSpan.FromMinutes(10), token);
        }
    }
    

    You can call this method when your application starts and Task.Wait the returned task before existing so you know it completes and has no exceptions:

    private Task _proccessSmsQueueTask;
    private CancellationTokenSource _cancellationTokenSource;
    
    protected override void OnStart(string[] args)
    {
        _cancellationTokenSource = new CancellationTokenSource();
        _proccessSmsQueueTask = Task.Run(() => DoWorkAsync(_cancellationTokenSource.Token));
    }
    
    protected override void OnStop()
    {
        _cancellationTokenSource.Cancel();
        try
        {
            _proccessSmsQueueTask.Wait();
        }
        catch (Exception e)
        {
            // handle exeption
        }
    }
    
    0 讨论(0)
提交回复
热议问题