AWS Lambda and SAM Gotchas

Thinking of utilising Amazon Web Services (AWS) Lambda services for your next API project? Maybe you’re even considering using the AWS Serverless Application Model (SAM) to speed up and simplify your AWS Lambda development process. This article will explore a few of the “gotchas” that took our team by surprise when using AWS Lambda and AWS SAM together.

While AWS Lambda provides low maintenance and cost-effective way to run quick running code in the Amazon Web Services cloud, you need to be aware that it is a different paradigm to traditional HTTP API services you may be familiar with. Therefore things you may take for granted in the old paradigm may not be the same or indeed possible at all with AWS Lambda. And while AWS SAM promises to simplify your AWS Lambda development process through abstractions and deployment via the AWS SAM command-line interface there are a few shortcomings and limitations that are useful to be aware of.

1. HTTP Error Status Codes aren’t the same as lambda errors

HTTP API errors aren’t the same as lambda errors. This has repercussions for your application telemetry. If you’re using CloudWatch alerts to monitor the number of errors you may only be detected a subset of the possible errors.

This is best illustrated with an example: say you have an HTTP POST endpoint that returns a 422 status code if the payload is missing a JSON field. In this instance, your lambda function would need to return an object containing the status code and a helpful message in the body. This means from the Lambda execution point of view your function has returned “successfully” and therefore in the monitoring tab in the AWS Console would show as successful execution.

In contrast say your code crashed in some kind of way, perhaps a null pointer exception causing the code to panic. This would cause the Lambda function to exit with an error. In which case the API Gateway would return a default error message and 500 status code. This would show up in the monitoring tab in the AWS Console as an error.

2. Third-Party Telemetry might not work the same way

Be aware that telemetry providers like NewRelic offer Lambda monitoring as a separate paid service to typical application monitoring that you may expect, typically via an agent. Not only does Lambda telemetry collection require more money but it also requires extra setup steps involving giving NewRelic access to your AWS accounts so it can ingest data from CloudWatch.

3. The AWS SAM command-line interface uses Docker

The AWS SAM can be used to run Lambda functions for local development purposes. This process uses Docker containers to trick your code to think it’s running on AWS. However, this means that if you are using the AWS SAM command-line interface as a part of your continuous integration pipelines you will either have to get it installed or mount the Docker socket into a container that has the AWS SAM command line interface installed and use Docker in Docker.

When using Docker in Docker mode you will need to add some extra flags to the SAM command so that it knows where to read the output from. You will need something like this:

docker run --rm \
    --net=host \
    --volume "${PWD}:${PWD}" \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    "${GO_SAM_BUILD_CONTAINER}" sam local invoke \
    --region ap-southeast-2 \
    --container-host "${DOCKER_HOST}" \
    --docker-volume-basedir "${PWD}" SomeLambdaFunction

If you are running this on macOS then the set DOCKER_HOST="host.docker.internal" and if you are using Linux then DOCKER_HOST="".

The variable GO_SAM_BUILD_CONTAINER should be a Docker container image with the SAM command line interface installed.

4. Lambda@Edge only supports Node.js and Python

Lambda@Edge is a service that lets you run Lambda functions at edge locations in AWS content delivery network. This means consumers can reduce latency by running their compute closer to their consumers. However, it’s important to be aware at the early stages of development that Lambda@Edge can only be used with a small subset of the possible languages that can be used with normal AWS Lambda. Currently, these languages are Node.js and Python. It is listed under Lambda@Edge on the Lambda FAQs page

5. There are limited official AWS SAM project templates

The AWS SAM command-line interface has a command to help you initialise your new projects sam init. Here you can select the language you would like to use and what other resources you would like to use with the Lambda. However, it is important to be aware that there are many different ways to set up a SAM project and services it can be integrated with beyond what is provided.

For example, if you are starting a new project using go1.x two templates are provided: “Hello World Example” and “Step Functions Sample App (Stock Trader)”. The Hello World Example sets you up with a Lambda function and an API Gateway, but if you are unfamiliar with AWS’s API Gateway you would not realise that there is a similar service called HTTP API Gateway has a slightly different feature set and is cheaper to use. Also, be aware that the API Gateway is publicly accessible by default.

6. AWS SAM Templates require a “build” stage before they can be used as CloudFormation Templates

You must use the AWS SAM command sam build which creates a build directory at ./.aws-build/ containing the build artefact.

At which point you can either now either use the AWS SAM command sam deploy to deploy your stack.

However, most enterprises have continuous integration and continuous delivery process and tooling which handles deploying CloudFormation. Therefore in this case we need another command sam package which will further modify our build artefact at ./.aws-sam/ by pushing our Lambda code to an S3 bucket and modifying the template further to reference the Lambda code in the S3 bucket.

It is only at this point that the template almost is used as a normal CloudFormation template. The only difference now is that you need to specify the Capability Auto Expand, see this link for more info on Capability Auto Expand.