0

I'm working on a c# application and using AWS lambda functions in the backend. The lambda function is working correctly and i'm able to call it from the application. The part I'm having trouble with is getting the code to wait for the result from the lambda function to be returned before continuing. I've looked into using the async/await pattern but i'm getting compile errors because AmazonLambda.InvokeAsync returns null.

This is the code what is correctly invoking the function and prints out the response but I'd like to instead return the response to the calling method. I've also tried changing the return from void to string and adding a return to the callback function but I get this error: "Anonymous function converted to a void returning delegate cannot return a value"

Any help is appreciated.

public void Invoke() {
    InvokeRequest invokeRequest = new InvokeRequest() {
    FunctionName = FunctionName,
    Payload = Payload
    };

    Client.InvokeAsync(invokeRequest, responseObject => {
        if (responseObject.Exception == null) {
            Debug.Log("LAMBDA SUCCESS: " + Encoding.ASCII.GetString(responseObject.Response.Payload.ToArray()));
        } else {
            Debug.Log("LAMBDA ERR: " + responseObject.Exception);
        }
    });
}
Drew MacLean
  • 640
  • 7
  • 13
  • that seems like a misuse of lambdas. your code shouldn't wait for another service to complete. – Daniel A. White Jul 30 '19 at 18:51
  • InvokeAsync is an async method. All async methods return a Task. Try adding await before the Involk async method, or add.GetAwaiter().GetResult() to the the end – JSON Jul 30 '19 at 18:52
  • You could use a `SemaphoreSlim` which you would release in the InvokeAsync callback, similar to here: https://stackoverflow.com/a/12858633/1223642 – Mike Guthrie Jul 30 '19 at 18:58

3 Answers3

0

Try...

var result = await Client.InvokeAsync(...

or

var result = Client.InvokeAsync(...).Result;
joelc
  • 2,687
  • 5
  • 40
  • 60
  • Damn beat me to it. Note that using the first method you will need to make your involke method async as well, along with everything else going down the stack trace. The second method will just make InvolkAsync run a a non async method – JSON Jul 30 '19 at 18:57
  • I got these two compile errors when trying the two different versions. Cannot await 'void' Operator '.' cannot be applied to operand of type 'void' – Drew MacLean Jul 30 '19 at 18:59
  • await Client.InvokeAsync() as var result doesn't work with void – Walter Verhoeven Jul 30 '19 at 19:09
0

Try

public async Task Invoke() {
    InvokeRequest invokeRequest = new InvokeRequest() {
    FunctionName = FunctionName,
    Payload = Payload
    };

   await Client.InvokeAsync(invokeRequest, responseObject => {
        if (responseObject.Exception == null) {
            Debug.Log("LAMBDA SUCCESS: " + Encoding.ASCII.GetString(responseObject.Response.Payload.ToArray()));
        } else {
            Debug.Log("LAMBDA ERR: " + responseObject.Exception);
        }
    });
}
Walter Verhoeven
  • 3,867
  • 27
  • 36
0

AmazonLambdaClient.InvokeAsync function have multiple overloads. The one which you are using accepts two parameters -

  1. InvokeRequest request
  2. AmazonServiceCallback

The second parameter is a callback, think of it as an event(just like a click event of a button). Which means it is called when an event has happened unlike async/await of C# which return values to caller.

This is an asynchronous operation using the standard naming convention for .NET 4.5 or higher. For .NET 3.5 the operation is implemented as a pair of methods using the standard naming convention of BeginInvoke and EndInvoke. For Unity the operation does not take CancellationToken as a parameter, and instead takes AmazonServiceCallback and AsyncOptions as additional parameters.

Here is the link to official documentation AmazonLambdaClient.InvokeAsync

To solve your problem -

public void Invoke() 
{
      InvokeRequest invokeRequest = new InvokeRequest
                                       {
                                            FunctionName = FunctionName,
                                            Payload = Payload
                                       };

   Client.InvokeAsync(invokeRequest, responseObject => 
   {
        if (responseObject.Exception == null) 
        {
             Debug.Log("LAMBDA SUCCESS: " + Encoding.ASCII.GetString(responseObject.Response.Payload.ToArray()));
             // Call function on success and pass in the returned value
        }
        else 
        {
            Debug.Log("LAMBDA ERR: " + responseObject.Exception);
             // Call function on failure and pass exception data
        }
   });
}

In the above code you can explicitly call methods for success/failure and pass in corresponding parameters. So whatever code you were planning to write after getting result from your Invoke function, write that in success/failure methods instead.

You can also create a separate callback function and use it instead of writing everything in Invoke function.

Gaurav Mathur
  • 804
  • 5
  • 14