1

I'm trying to understand async methods and await, I've got this simple example:

using (var client = new AmazonSQSClient())
{
    var sqsRequest = new SendMessageRequest()
    {
        MessageBody = JsonConvert.SerializeObject(callProcessingRequest),
        QueueUrl = "https://sqs.eu-west-2.amazonaws.com/*****6014/W*****g"
    };

    LoggingHelper.Log(LoggingLevel.INFO, "Calling SQS", context);

    var sqsResponse = await client.SendMessageAsync(sqsRequest);

    LoggingHelper.Log(LoggingLevel.DEBUG,
        JsonConvert.SerializeObject(sqsResponse), context)
}

When I run this, the logging of sqsResponse never happens, however if I change

var sqsResponse = await client.SendMessageAsync(sqsRequest);

to

var sqsResponse = client.SendMessageAsync(sqsRequest).Result;

Then it works as expected.

With it being an async method I guess I should be using await with it, but not sure why it's not working.

EDIT: Whole method as requested. Adding .ConfigureAwait(false) didn't help.

public static async Task ProcessOutstandingDialplanItems()
{
    var context = new Context() { CurrentHandler = "PBXCallbacksLambdaFunction" };

    var callProcessingRequest = new CallProcessingRequest()
    {
        context = context,
        MethodToInvoke = "ProcessOutstandingDialPlanItems"
    };

    try
    {
        using (var client = new AmazonSQSClient())
        {
            var sqsRequest = new SendMessageRequest()
            {
                MessageBody = JsonConvert.SerializeObject(callProcessingRequest),
                QueueUrl = "https://sqs.eu-west-2.amazonaws.com/XXX6014/WXXXg"
            };

            LambdaLogger.Log("Calling SQS");

            var sqsResponse = await client.SendMessageAsync(sqsRequest)
                .ConfigureAwait(false);
            //var sqsResponse = client.SendMessageAsync(sqsRequest).Result;

            LambdaLogger.Log(JsonConvert.SerializeObject(sqsResponse));
        }
    }
    catch (Exception x)
    {
        LambdaLogger.Log(x.Message);
    }   
}
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Ben
  • 609
  • 6
  • 21
  • 1
    Don’t call result. It can deadlock – Daniel A. White Jan 20 '23 at 22:53
  • If `await` doesn't work but `.Result` does, it could be some obscure problem related to the resuming thread not being the initial one, and your logging service relying on it. In which context is this code running ? C# console app ? ASP.NET ? – Arthur Attout Jan 20 '23 at 22:57
  • It's an AWS Lambda function (C# / .NET core) – Ben Jan 20 '23 at 22:58
  • What are you using for logging? Can it be something which depends on the current thread? – Mike Mozhaev Jan 20 '23 at 23:32
  • How are you using the `ProcessOutstandingDialplanItems` method? Are you `await`ing it asynchronously, or you are `Wait`ing it synchronously? Could you include that specific line in the question? – Theodor Zoulias Jan 21 '23 at 17:18
  • Please check if this helps: https://stackoverflow.com/questions/57586886/net-core-aws-lambda-function-not-flushing-logs – Mike Mozhaev Jan 21 '23 at 17:51
  • 1
    How do you call `ProcessOutstandingDialplanItems` function? Are you using `await` up to the entrypoint? – Mike Mozhaev Jan 21 '23 at 18:05

2 Answers2

1

From AWS Logging .NET:

AWS Lambda

These packages batch logging messages in a queue and send messages to CloudWatch Logs using a background thread. The use of the background thread means that the messages are not guaranteed to be delivered when used in AWS Lambda. The reason is because the background thread will be frozen once a Lambda event is processed and may not ever be unfrozen if more Lambda events are not received for some time.

When using Lambda it is recommended to use either the ILambdaContext.Logger.LogLine or the Amazon.Lambda.Logging.AspNetCore package.

Mike Mozhaev
  • 2,367
  • 14
  • 13
0

My guess would be that you are already using Result or Wait (or something which is calling your code) in one of the method before in application which has SynchronizationContext (classic ASP.NET, UI apps like WPF, WinForms, etc.). That is a "good" way to end up in deadlock. One thing you can try - adding ConfigureAwait(false) to the call:

var sqsResponse = await client.SendMessageAsync(sqsRequest).ConfigureAwait(false);

But much better course of action - Don't Block on Async Code.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • Weird blog post. His first best practice is "just a hack"? (His words, not mine) – David Libido Jan 20 '23 at 23:36
  • 2
    @DavidLibido yes, you can consider it as one. Also post author definitely knows his stuff, so I would recommend to take his opinion in account) – Guru Stron Jan 20 '23 at 23:40
  • I'm sure he does but I will not consider using these kind of "best practices" in my code. – David Libido Jan 20 '23 at 23:48
  • 2
    @DavidLibido: Using `ConfigureAwait(false)` in library code is a best practice. Using `ConfigureAwait(false)` to avoid deadlocks is a hack. Hopefully this clears that up. – Stephen Cleary Jan 22 '23 at 01:26