Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Await Task Not returning after completion

I'm having an issue where a task is completing, but not returning back. I have a website and a web service on different servers. The website makes a call to the web service which utilizes a library with function myFunction(). If I make a call to myFunction from a console app on the web service's server, it will return as expected. However, when I make the call from the website to the web service to call myFunction(), it will get to "Step 3", but not "Step 4". I have a simplified version of the calls below.

private string myFunction()
{
    string myStr = myDoWork().GetAwaiter().GetResult();

    return myStr;
}

private async Task<string> myDoWork()
{
    logger.Debug("Step 1");
    string answer = await aFunction();

    logger.Debug("Step 4");

    return answer;
}

public async Task<string> aFunction()
{
    logger.Debug("Step 2");
    return await bFunction(CancellationToken.None);
}

AsyncLock myLock = new AsyncLock();
public Task<string> bFunction(CancellationToken cToken)
{
    return Task.Run(
        async () =>
        {
            using (await myLock(cToken))
            {
                logger.Debug("Step 3");
                result = "Hello";
                return result;
            }
        },
        cToken);
}

I'm new to async and await, so any help would be appreciated.

like image 906
Jesse McConahie Avatar asked May 13 '16 19:05

Jesse McConahie


People also ask

How do I return from async Task?

If you use a Task return type for an async method, a calling method can use an await operator to suspend the caller's completion until the called async method has finished. In the following example, the WaitAndApologizeAsync method doesn't contain a return statement, so the method returns a Task object.

What happens if you don't await a Task?

If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.

Should you return the Task or await?

The only time we truly want to await is when we do something with the result of the async task in the continuation of the method. Note that if we don't have return await, but return a Task<T> instead, the return happens right away, so, if the code is inside a try/catch block, the exception will not be caught.

Is an async method that returns Task a return keyword?

DoSomething()' is an async method that returns 'Task', a return keyword must not be followed by an object expression.


1 Answers

It's almost certainly a deadlock in myFunction(). Step 4 is scheduled to execute on the main thread, but it can't because the main thread is blocked waiting on GetResult().

It should be something closer to this:

private string myFunction()
{
    // This is NOT good style - you should avoid blocking on the result of a task.
    string myStr = Task.Run(async () => await myDoWork()).GetAwaiter().GetResult();
    return myStr;
}

private async Task<string> myDoWork()
{
    logger.Debug("Step 1");
    string answer = await aFunction();
    logger.Debug("Step 4");
    return answer;
}

public Task<string> aFunction()
{
    logger.Debug("Step 2");
    return bFunction(CancellationToken.None);
}

AsyncLock myLock = new AsyncLock();
public async Task<string> bFunction(CancellationToken cToken)
{
    using (await myLock(cToken))
    {
        logger.Debug("Step 3");
        return "Hello";
    }
}

In general, Task.Run() should be called from the highest level possible. Keep things as synchronous as possible and let the caller decide if they want to use a background thread.

like image 187
piedar Avatar answered Oct 15 '22 15:10

piedar