Corey
Corey

Reputation: 498

Calling AWS Lambda Function in C#

I'm trying to run a Lambda function from a console application. The idea is for it to run a quick fire & forget lambda function without waiting for lambda function to return. My code doesn't appear to be executing the lambda function at all though. I know the function works because I can run with the test. When I run the below code I just get a task cancelled exception.

var jsonSerializer = new JsonSerializer();
var lambdaConfig = new AmazonLambdaConfig() { RegionEndpoint = RegionEndpoint.USEast2 };
var lambdaClient = new AmazonLambdaClient(lambdaConfig);

using (var memoryStream = new MemoryStream())
{
    jsonSerializer.Serialize(myData, memoryStream);
    var lambdaRequest = new InvokeRequest
    {
        FunctionName = "MyFunction",
        InvocationType = "Event",
        PayloadStream = memoryStream
};

var result = Task.Run(async () => { return await lambdaClient.InvokeAsync(lambdaRequest); }).Result;

Does anyone have some insight into what I'm doing wrong?

Thanks!

Upvotes: 5

Views: 20456

Answers (4)

Demarsch
Demarsch

Reputation: 1479

I believe there are two issues in your code:

  • (Mentioned by @Nikosi) You dispose your memoryStream before it is used for lambda invocation
  • (The fix that helped in my case) When you serialize you payload into memory stream, the position in the stream points to the byte after its end and thus SDK has nothing to read from it. So I just used memoryStream.Seek(0L, SeekOrigin.Begin)

By the way, assuming that JsonSerializer is the one from Newtonsoft.Json package, I didn't find Serialize method that accepts Stream parameter, only TextWriter or JsonWriter. So it might be necessary to wrap it into StreamWriter and make sure you call Flush or FlushAsync (or dispose StreamWriter before using memory stream as Lambda payload) like this:

await using var stream = new MemoryStream();
await using var streamWriter = new StreamWriter(stream);
var serializer = new JsonSerializer();
serializer.Serialize(streamWriter, payload);
await streamWriter.FlushAsync();
stream.Seek(0L, SeekOrigin.Begin);

log.LogInformation("Batch {0}: sending {1} messages to Lambda", batchId, batch.Count);

var lambdaResponse = await lambda.InvokeAsync(new InvokeRequest
{
    InvocationType = InvocationType.RequestResponse,
    PayloadStream = stream,
    //Payload = JsonConvert.SerializeObject(payload),
    FunctionName = lambdaArn
}, stoppingToken);

Upvotes: 4

Vikash Rathee
Vikash Rathee

Reputation: 2104

You can pass your myData directly instead converting into MemoryStream, if the data is a valid JSON with double quotes.

In function name you can use the ARN or just the name. Both works fine for me in latest version AWSSDK.Lambda -Version 3.3.103.31

static readonly string awsAccessKey = "access key here";
static readonly string awsSecretKey = "secret key here";

private static BasicAWSCredentials awsCredentials = new BasicAWSCredentials(awsAccessKey, awsSecretKey);
private static AmazonLambdaConfig lambdaConfig = new AmazonLambdaConfig() { RegionEndpoint = RegionEndpoint.USEast1 };
private static AmazonLambdaClient lambdaClient = new AmazonLambdaClient(awsCredentials, lambdaConfig);

public async Task<string> GetLambdaResponse(string myData)
{
    var lambdaRequest = new InvokeRequest
    {
        FunctionName = "mylambdafunction",
        Payload = myData
    };

    var response = await lambdaClient.InvokeAsync(lambdaRequest);
    if (response != null)
    {
        using (var sr = new StreamReader(response.Payload))
        {
            return await sr.ReadToEndAsync();
        }
    }
    return string.Empty;        
}

Upvotes: 9

ranni rabadi
ranni rabadi

Reputation: 324

The FunctionName in Nkosi's answer should actually be the entire ARN to your lambda function, so taking from Nkosi's answer:

public static void Main(string[] args) {    
var jsonSerializer = new JsonSerializer();
var lambdaConfig = new AmazonLambdaConfig() { RegionEndpoint = RegionEndpoint.USEast2 };
var lambdaClient = new AmazonLambdaClient(lambdaConfig);

var memoryStream = new MemoryStream();

jsonSerializer.Serialize(myData, memoryStream);
var lambdaRequest = new InvokeRequest
{
    FunctionName = "arn:aws:lambda:ap-southeast-2:{id}:function:MyFunction",
    InvocationType = "Event",
    PayloadStream = memoryStream
};

lambdaClient.InvokeAsync(lambdaRequest);

Console.ReadLine();

Upvotes: 3

Nkosi
Nkosi

Reputation: 247561

Mixing blocking calls could be causing a deadlock. If the intent is to fire and for get then just call the desired function. Also why give request a stream only to dispose of it after wards

public static void Main(string[] args) {    
    var jsonSerializer = new JsonSerializer();
    var lambdaConfig = new AmazonLambdaConfig() { RegionEndpoint = RegionEndpoint.USEast2 };
    var lambdaClient = new AmazonLambdaClient(lambdaConfig);

    var memoryStream = new MemoryStream();

    jsonSerializer.Serialize(myData, memoryStream);
    var lambdaRequest = new InvokeRequest
    {
        FunctionName = "MyFunction",
        InvocationType = "Event",
        PayloadStream = memoryStream
    };

    lambdaClient.InvokeAsync(lambdaRequest);

    Console.ReadLine();
}

Upvotes: 3

Related Questions