Best way to do a task looping in Windows Service

async-await, c#, multithreading, task-parallel-library, windows-services

Solution

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

Problem

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: I don´t know how long it takes for the method run; The method can throw exceptions, that I want to write on EventLog 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.

Original source

Related problems