web-dev-qa-db-ja.com

Windowsサービスでタスクループを実行する最良の方法

以下のようないくつかのSMSをお客様に送信する方法があります。

_public void ProccessSmsQueue()
{
   SmsDbContext context = new SmsDbContext();
   ISmsProvider provider = new ZenviaProvider();
   SmsManager manager = new SmsManager(context, provider);

   try
   {
      manager.ProcessQueue();
   }
   catch (Exception ex)
   {
      EventLog.WriteEntry(ex.Message, EventLogEntryType.Error);
   }
   finally
   {
      context.Dispose();
   }
}

protected override void OnStart(string[] args)
{
   Task.Factory.StartNew(DoWork).ContinueWith( ??? )
}
_

だから、私はいくつかの問題があります:

  1. メソッドの実行にかかる時間はわかりません。

  2. メソッドは、EventLogに書き込みたい例外をスローできます

  3. このメソッドをループで10分ごとに実行したいただし、最後の実行が終了した後のみ

どうすればこれを達成できますか? ContinueWith()の使用を検討しましたが、ロジック全体の構築方法についてまだ質問があります。

16
GuFigueiredo

CancellationTokenを受け入れる非同期メソッドが必要です。これにより、停止するタイミングを認識し、try-catchブロックでProccessSmsQueueを呼び出し、Task.Delayを使用して次まで非同期に待機します。実行に必要な時間:

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

アプリケーションの起動時にこのメソッドを呼び出し、存在する前に返されたタスクをTask.Wait呼び出すことができるため、タスクが完了し、例外がないことがわかります。

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
    }
}
33
i3arnon

Windowsサービスで使用したサンプルワーカークラス。ロックを使用して「クリーン」な方法で停止をサポートします。 DoWorkにコードを追加し、タイマーをStartTimerAndWorkメソッド(ミリ秒単位)に設定して、このクラスをサービスで使用するだけです。

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

    }
1
Adrian Nasui