Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to do a task looping in Windows Service

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

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( ??? )
}

So, I have some issues:

  1. I don´t know how long it takes for the method run;

  2. The method can throw exceptions, that I want to write on EventLog

  3. I want to run this method in loop, every 10 min, but only after last execution finish.

How I can achieve this? I thought about using ContinueWith(), but I still have questions on how to build the entire logic.

like image 224
GuFigueiredo Avatar asked Nov 28 '14 13:11

GuFigueiredo


People also ask

How do I run a Windows service continuously in C#?

Inside the loop, we sleep for 1 second. You'll want to replace this with the work you need to do - monitor proxy settings, etc. Finally, in the OnStop() callback of your Windows Service, you want to signal the thread to stop running. This is easy using the _shutdownEvent .

Should I use Task or thread?

It is always advised to use tasks instead of thread as it is created on the thread pool which has already system created threads to improve the performance. The task can return a result. There is no direct mechanism to return the result from a thread.

Does Task run Use thread pool?

The main purpose of Task. Run() is to execute CPU-bound code in an asynchronous way. It does this by pulling a thread from the thread pool to run the method and returning a Task to represent the completion of the method.


1 Answers

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
    }
}
like image 107
i3arnon Avatar answered Sep 28 '22 08:09

i3arnon