HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Asynchronously wait for a task to complete and do some async action while waiting

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
whilewaitasyncwaitingactioncompleteforasynchronouslysomeand

Problem

I have a long-running task. My goal is to create a method that will allow me to:

  • Asynchronously wait for this task to complete



  • While waiting on a task, do some async action once in a while. This


'action' basically tells some remote service that task is not dead
and still executing.

I've written the following code to solve this problem. Please have a look and share your thoughts!

public delegate Task AsyncAction();

public static class TaskExtensions
{
    public static async Task TimeoutAfter(this Task task, TimeSpan timeout)
    {
        var timeoutCancellationTokenSource = new CancellationTokenSource();

        var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token)).ConfigureAwait(false);
        if (completedTask == task)
        {
            timeoutCancellationTokenSource.Cancel();
            await task.ConfigureAwait(false);
            return true;
        }
        else
        {
            return false;
        }
    }

    public static async Task AwaitWithTimeoutCallback(this Task task, TimeSpan timeout, AsyncAction onTimeout)
    {
        while (true)
        {
            var completed = await task.TimeoutAfter(timeout).ConfigureAwait(false);
            if (completed)
            {
                break;
            }

            await onTimeout().ConfigureAwait(false);
        }

        await task.ConfigureAwait(false);
    }
}


Usage:

var task = Task.Delay(TimeSpan.FromSeconds(15));

task.AwaitWithTimeoutCallback(TimeSpan.FromSeconds(5), () =>
{
    Console.WriteLine("Waiting...");
    return Task.FromResult(true);
})
.Wait();

Solution

public delegate Task AsyncAction();


Instead of creating a custom delegate type, you could just reuse Func (even though logically, it is an action and not a function).

return Task.FromResult(true);


Consider adding an overload that takes a non-async onTimeout delegate, so that this confusing code wasn't required.

Or, if you do something like this often, have some TaskEx.Completed, or something like that.

Otherwise, good job. I especially like that you remembered to use ConfigureAwait(false) everywhere.

Code Snippets

public delegate Task AsyncAction();
return Task.FromResult(true);

Context

StackExchange Code Review Q#70836, answer score: 2

Revisions (0)

No revisions yet.