在Windows服务中执行任务循环的最佳方法

我有一种方法可以向我们的客户发送一些短信,如下所示:

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. 该方法可以抛出exception,我想在EventLog上编写

  3. 我希望每10分钟在循环中运行此方法, 但只能在最后一次执行完成后运行。

我怎么能做到这一点? 我想过使用ContinueWith() ,但我仍然对如何构建整个逻辑有疑问。

您应该有一个异步方法接受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); } } 

您可以在应用程序启动时调用此方法,并在返回任务之前将其返回任务,以便您知道它已完成并且没有例外:

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

我在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 }