3

I have the following code:

public async Task SendPushNotificationAsync(string username, string message)
{
    var task = ApnsNotifications.Instance.Hub.SendAppleNativeNotificationAsync(alert, username);
    if (await Task.WhenAny(task, Task.Delay(500)) == task) {
       return true;
    }
    return false;
}

I noticed that SendAppleNativeNotificationAsync was hanging indefinitely (never returning out of the containing method), so I tried telling it to cancel after 500ms. But still... the call to WhenAny now hangs and I never see a return get hit, resulting in the consumer just waiting indefinitely (it's a sync method calling this async method, so I call .Wait()):

_commService.SendPushNotificationAsync(user.Username, notificationDto.PushContent).Wait(TimeSpan.FromSeconds(1));

How do I force this to finish after a set time, no matter what?

What happens if I simply "fire and forget", instead of awaiting the Task?

Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
SB2055
  • 12,272
  • 32
  • 97
  • 202
  • Where do you execute this code? I mean, web application, desktop application, maybe mobile? – Evk Nov 01 '16 at 16:08
  • @Evk this is in a service method called from a sync service method, called by a WebApi controller. – SB2055 Nov 01 '16 at 16:09
  • 2
    Don't ever use Wait (or Task.Result) together with async\await in environments with "UI" or "request" thread - it will deadlock just like you observe. – Evk Nov 01 '16 at 16:17
  • @Evk is this "Deadlock" or just "blocking until something finishes"? – SB2055 Nov 01 '16 at 16:44
  • This is deadlock, but the reasons I cannot explain in comments, you can see them in duplicate question. – Evk Nov 01 '16 at 17:19

1 Answers1

5

it's a sync method calling this async method, so I call .Wait()

And that's your problem. You're deadlocking because you're blocking on asynchronous code.

The best solution for this is to use await instead of Wait:

await _commService.SendPushNotificationAsync(user.Username, notificationDto.PushContent);

If you absolutely can't use await, then you can try one of the hacks described in my Brownfield Async article.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Thanks for this. If I use `await` and `SendAppleNativeNotificationAsync` never returns, will I be ok? – SB2055 Nov 01 '16 at 16:34
  • @SB2055: Why would it never return? – Stephen Cleary Nov 01 '16 at 17:12
  • I'm basing that on the behavior I'm seeing from my debugger - I can never catch a `return` but maybe that's because another thread is picking it up? – SB2055 Nov 01 '16 at 17:14
  • 1
    @SB2055: Blocking on it will *prevent* completion. If you `await` it, it should work fine. – Stephen Cleary Nov 01 '16 at 17:22
  • @StephenCleary I'm having this exactl problem in an async method. When setting a breakpoint an an await, the next line of code is never invoked with the task hanging, despite the message being delivered to the endpoint. – Philipp Sumi Jan 28 '17 at 15:45
  • I'm also having this exactl problem in an async method. When setting a breakpoint an an await, the next line of code is never invoked with the task hanging, despite the message being delivered to the endpoint – Qasim Jan 30 '17 at 21:22