We have utilized Amazon Serverless Architecture for a few critical parts of our system that needs to be always running. Using the ASP.NWT Core template that's offered by AWS tools to create and deploy the solution is up and running in no time. Now a couple of our operations are time-sensitive, and AWS has indicated that lambda will live for about 15 minutes, this is only for the first instance. Due to the nature of our system, those lambdas will get hit excessively by the outside world through an API Gateway proxy, so because one instance can't handle the load we need 4-5 instances of this lambda to be running simultaneously.
Environment
Net core got a major improvement in v3 with ReadyToRun (AOT) deploy mode, which would boost the cold start of the lambda function, but custom runtimes didn't get much good feedback from the industry so we went for v2.1, latest supported runtime as of this writing.
CloudWatch to ping lambda
The recommended approach to keep a lambda instance alive is to set up a CloudWatch
event that will ping the lambda endpoint periodically.
To set up CloudWatch event rule just hit CloudWatch
in your AWS console, the open Rules
submenu, and click Create.
- Choose
Schedule
as the event source - Pick target the one lambda you want to keep running
- Configure Input as Constant (JSON text)
- Add the payload that will hit the function entry point
{ "Resource": "KeepAliveClickLambda", "Body": 5 }
Lambda FunctionHandler
The default project template comes with two entry points, LocalEntryPoint
used for local debugging and the LambdaEntryPoint
one used by AWS infrastructure. We need to override the FunctionHandler method behavior to listen for our CloudWatch call and keep up the number of instances defined in the Body JSON payload. Also for the lambda to call itself we need to install AWSSDK.Lambda NuGet package.
public override async Task<APIGatewayProxyResponse> FunctionHandlerAsync(APIGatewayProxyRequest request, ILambdaContext lambdaContext)
{
if (request.Resource == "KeepAliveClickLambda")
{
// this is a hit from CloudWatch cron job, or lambda itself
if (int.TryParse(request.Body, out int totalInstances))
{
if (totalInstances > 1)
{
// we need to repeat this call for number of instances defined in payload, minus this one
var client = new AmazonLambdaClient();
await client.InvokeAsync(new Amazon.Lambda.Model.InvokeRequest
{
FunctionName = lambdaContext.FunctionName,
InvocationType = InvocationType.RequestResponse,
Payload = JsonConvert.SerializeObject(new APIGatewayProxyRequest
{
Body = (totalInstances - 1).ToString(),
Resource = request.Resource
})
});
}
}
return new APIGatewayProxyResponse();
}
return await base.FunctionHandlerAsync(request, lambdaContext);
}
Summary
With this in place, the keep-alive function should be up and running, so we are good for now.