Triggering a .NET Lambda Function from an Amazon SQS Queue

Want to learn more about AWS Lambda and .NET? Check out my A Cloud Guru course on ASP.NET Web API and Lambda.

Download full source code.

This post will show how to trigger a .NET Lambda function when a message arrives in Amazon SQS queue.

You will see how to

  • create the SQS queue
  • create and configure the Lambda function to receive messages from the queue,
  • how to add messages to the queue

Create the SQS Queue

From the command line run -

aws sqs create-queue --queue-name my-first-queue  

You should see output like -

aws sqs create-queue --queue-name my-first-queue  
{
    "QueueUrl": "https://sqs.us-east-1.amazonaws.com/1234567890/my-first-queue"
}

Take note of the QueueUrl. You will need it shortly.

That’s all there is to creating the queue.

Create, deploy, and configure the Lambda Function

Now you will create a Lambda function to read from the queue. It’s going to take in an SQSEvent, this event can have multiple records/messages in it. Each message will be processed by the function, and the output written to CloudWatch logs.

You could of course do more with the message, but this is just a simple example.

Creating the function

From the command line run -

dotnet new lambda.SQS -n SQSConsumer 

Change to the SQSConsumer/src/SQSConsumer directory.

Replace the contents of the Function.cs file with the following code -

using Amazon.Lambda.Core;
using Amazon.Lambda.SQSEvents;
using System.Text.Json;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace SQSConsumer;

public class Function
{
    DateTime _today;
    public Function()
    {
         _today = DateTime.Today;
    }
    public async Task FunctionHandler(SQSEvent sqsEvent, ILambdaContext context)
    {
        foreach(var message in sqsEvent.Records)
        {
            await ProcessMessageAsync(message, context);
        }
    }

    private async Task ProcessMessageAsync(SQSEvent.SQSMessage message, ILambdaContext context)
    {
        context.Logger.LogInformation($"Processed message {message.Body}");
        var person = JsonSerializer.Deserialize<Person>(message.Body);
        var age = _today.Year - person.DateOfBirth.Year;
        if (person.DateOfBirth.Date > _today.AddYears(-age)) age--;
        person.Age = age;
        context.Logger.LogInformation(person.ToString());        
        await Task.CompletedTask;
    }
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public int Age { get; set; }
    public override string ToString()
    {
        return $"{FirstName}  {LastName} was born on {DateOfBirth} and is {Age} years old";
    }
}

There are a few things to note in the above code -

  • lines 16-22, the FunctionHandler receives the SQSEvent, loops over the messages/records in it, and calls the ProcessMessageAsync method for each message.
  • lines 24-33, processes the message, first logging the raw message. Then doing a simple calculation to get the age of the person. Finally, it logs the output to CloudWatch logs.

That’s all there is to it.

Deploying the function

To deploy the function run -

dotnet lambda deploy-function SQSConsumer

You will be asked - “Select IAM Role that to provide AWS credentials to your code:”, select “*** Create new IAM Role ***”

You will then be asked - “Enter name of the new IAM Role:”, put in “SQSConsumer”.

Then you will be asked to - “Select IAM Policy to attach to the new role and grant permissions”, select “AWSLambdaSQSQueueExecutionRole”, for me it is number 4 on the list.

This policy will give the Lambda function permission to receive/delete messages from the SQS queue.

Configuring to be triggered when messages are added to the queue

At this point, the Lambda function is deployed and ready to run, but it is not configured to be triggered when messages are added to the queue.

To do this run -

aws lambda create-event-source-mapping --function-name SQSConsumer --batch-size 10  --maximum-batching-window-in-seconds 5 --event-source-arn arn:aws:sqs:us-east-1:540405075872:my-first-queue

Now when a message is added to the queue, the Lambda function will be triggered.

Adding messages to the queue

You can add messages to the queue from SQS UI in the AWS Console, from the AWS CLI, or from a simple C# console application.

Create a new console application and add two NuGet packages - Bogus and AWSSDK.SQS.

Then replace the contents of the Program.cs file with the following code, making sure to update the QueueUrl to your queue -

using Amazon.SQS;
using Bogus;
using System.Text.Json;

var people = People.GetList(2);
AmazonSQSClient client = new AmazonSQSClient();

foreach (var person in people)
{
    Console.WriteLine($"Sending {person.FirstName} {person.LastName} to SQS... ");
    await client.SendMessageAsync( new Amazon.SQS.Model.SendMessageRequest
    {
        QueueUrl = "https://sqs.us-east-1.amazonaws.com/1234567890/my-first-queue",
        MessageBody = JsonSerializer.Serialize(person)
    });
}

public class People
{
    public static IEnumerable<Person> GetList(int count)
    {
        var personFaker = new Faker<Person>()
            .RuleFor(p => p.FirstName, f => f.Name.FirstName())
            .RuleFor(p => p.LastName, f => f.Name.LastName())
            .RuleFor(p => p.DateOfBirth, f => f.Date.Past(100));
        
        return personFaker.Generate(count);
    }
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
}

Run the console application, it will create two messages and add them to the queue.

Then go to your Lambda function, choose the Monitor tab, and click View CloudWatch logs. In CloudWatch logs, open the most recent stream (it can take a minute for logs to show up) and you should see the output from the Lambda function.

Download full source code.

comments powered by Disqus

Related