AWS Lambda is well known for the amazing scalability and extremely easy integrations with the AWS cloud native event producers, i.e. SQS, SNS, CloudWatch just to mention a few. However, there is another interesting aspect of it — invoking AWS Lambda synchronously, for example running a RESTful API.
TL; DR;
Lambda can be invoked synchronously (1) via AWS Console/CLI/SDK, (2) API Gateway, and (3) Application Load Balancer (ALB). The source code of the examples is available on my GitHub here.
Invoke AWS Lambda synchronously
In certain situations you may want to invoke Lambda synchronously, i.e. wait for the response be returned back to you. The classic example is API where almost always you need to return response to the caller. In this blog post I will review different ways of invoking AWS Lambda synchronously.
1. Directly via AWS Console / CLI / SDK
I’ve grouped these three methods together, since all of them are direct invocations.
AWS Console
The most obvious and perhaps the least useful method :) It’s useful only for a quick test after creating a Lambda. Just configure a test event, and it’s enough to press Test button whenever you want to test your Lambda with the pre-configured payload.
AWS CLI
Similarly, you can invoke Lambda directly using AWS CLI. Just make sure you are authenticated against AWS. I used Nike’s gimme-aws-creds tool which works really well with Okta SSO.
The following command would invoke Lambda from Windows command prompt or any other similar tool like Cmder.
aws lambda invoke --function-name "1-direct-invocation" --invocation-type "RequestResponse" --payload "{\"Records\":[{\"Body\":\"Hello Lambda!\"}]}" response.json
The important bit is the invocation type, which by default is the RequestResponse and forces Lambda to be invoked synchronously.
This might be useful if you have to invoke lambda from an EC2 instance or some automation script, and want to keep the application code separately.
AWS Lambda SDK
Similarly to the CLI method, you can invoke Lambda from your .NET code by simply providing function name, RequestResponse invocation type, and JSON payload.
var client = new AmazonLambdaClient();
var sqsEvent = new SQSEvent
{
Records = new List<SQSEvent.SQSMessage>
{
new SQSEvent.SQSMessage
{
Body = "Hello Lambda!"
}
}
};
var request = new InvokeRequest
{
FunctionName = "1-direct-invocation",
// force sync lambda invocation
InvocationType = InvocationType.RequestResponse,
LogType = LogType.Tail,
Payload = JsonSerializer.Serialize(sqsEvent)
};
var result = await client.InvokeAsync(request);
I left the default credentials config and let the SDK to pick up the authentication credentials automatically. Again, used the previously mentioned gimme-aws-creds.
And I struggled to come up with a useful and realistic example though. If you have an interesting use-case — please leave in comments :)
2. API Gateway
Perhaps the most well known synchronous Lambda invocation method. It allows to create public and private APIs with Lambda’s backend.
In this exercise, I created API Gateway with HTTP API flavour, and proxy+ integration with a single Lambda to route all the requests to that Lambda function.
I used Amazon.Lambda.AspNetCoreServer nuget package to run ASP.NET Core Web API inside Lambda, hence if needed, could leverage pretty much any nuget package or middleware you would use with any other ASP.NET Core Web API. See LambdaAspNetCoreServerHttpApiV2 project for the source code.
Important! HTTP API needs APIGatewayHttpApiV2ProxyFunction base class set in LambdaEntryPoint class, since it uses a new event contract (compared to API Gateway’s REST API). The older APIGatewayProxyFunction results in NullReferenceException.
Once the Lambda is published and API Gateway stage is deployed, I used Postman to send a GET request to the API.
ASP.NET Core handles request routing, serializing/deserializing, DI is available out of the box, and there are tons of useful nuget packages available. Of course, it’s possible to use multiple Lambda integrations in a single API Gateway as well, however it’s extremely convenient to develop an API using a single Lambda function only.
3. Application Load Balancer (ALB)
It seems natural to think of API Gateway when someone mentions Lambda backed API, however as of writing this blog post, API Gateway doesn’t support private DNS. Meaning, if you have to create an API inside your VPC, you would always have a raw API Gateway URL e.g. https://1234567890.execute-api.eu-west-1.amazonaws.com which could change if you deleted and re-created your API. Also, inside VPC you might prefer to use HTTP instead of HTTPS which could be quite challenging with API Gateway.
ALB solves this issue! You can use both public and private ALBs with Lambda!
I’ve created a public ALB in two different subnets with a Security Group allowing requests from my IP address. And the magical setup happens in Target Group where Lamba target type could be specified.
I left the health check out, however a frequent health check might help to keep your Lambda warm :)
My ALB has only one listener rule to send all the traffic to the Lambda target group.
I used a very similar Lambda function code as in the API Gateway example, just set the base class to ApplicationLoadBalancerFunction. See LambdaAspNetCoreServerAlb project for the source code.
Once the Lambda is published, I’ve used Postman to send a GET request to the ALB.
I come from ECS background and using Lambda with ALB feels like using a lightweight and fully managed Docker :) Especially, when using Amazon.Lambda.AspNetCoreServer to run Asp.NET Core Web API inside Lambda.
Conclusions
AWS Lambda offers a lot of different integrations, and even multiple ways to invoke it synchronously.
I demonstrated 3 different ways to invoke AWS Lambda synchronously — directly via AWS Console / CLI / SDK, API Gateway and Application Load Balancer (ALB).
The source code could be found on my GitHub, and I used Amazon.Lambda.AspNetCoreServer nuget package to run the whole ASP.NET Core Web API inside Lambda in API Gateway and ALB examples.