Locally Debug Your Serverless Function

Posted in: Cloud, DevOps

Serverless architecture opens an exciting new space for building cloud-native and event-driven applications. By going serverless development teams focus on business logic while leveraging managed services. But this new approach raises new questions. When all the infrastructure is on the cloud, how do you have a productive local development environment? Can you even run serverless functions locally, let alone debug them?

Fortunately, a number of techniques exist to make working with serverless functions painless and productive. We’ll use Node.js and AWS Lambda to demonstrate a couple ways of invoking and debugging functions locally. After following this guide, you’ll have the confidence to start debugging Lambda’s of your own.

I’ll use an example application to show how to run and debug an AWS Lambda function locally. The application is a single function backed by a dataset of Lord of the Rings characters in DynamoDB. The function searches the database for characters with a given trait, like “fellowship,” and returns the matching characters as JSON. This creates a dependency on DynamoDB, so even when running locally, we will be connecting to DynamoDB to do the table scan.

To demonstrate debugging, I’ll be providing the setup for two popular IDEs/editors: Microsoft Visual Studio Code and JetBrain’s Webstorm.

Tip If you’d like to follow along, clone this git repo http://github.com/rshurts/lambda-debug-example, follow the instructions in the README.md, and return to the blog.

Serverless Framework

My go-to framework for creating Lambda functions is the Serverless Framework. Serverless manages the entire lifecycle of the Lambda and can even deploy required services using Cloud Formation. Check it out if you are looking to build your own serverless application.

Here we’re going to take advantage of the fact that the Serverless Framework can invoke functions locally. And use that invocation to setup local debugging. Use the following command, where -f identifies the function name and -p is the path to the request payload:

sls invoke local -f findCharactersByTag -p examples/findCharactersByTag.json

Normally when a Lambda runs it assumes an IAM role. However, when Serverless invokes the function locally it uses your default AWS profile. Meaning it isn’t an exact simulation of AWS. Read more about the difference in the Serverless docs.

Visual Studio Code and Serverless

Visual Studio Code manages debugging through launch configurations. Open the Debug panel and create a new Node.js launch configuration. Add the following to the launch.json:

To begin debugging, set some breakpoints and perform the following steps:

  1. Select findCharacterByTag from the configurations select box.
  2. Click the Start Debugging button.
  3. Use the debugger buttons to step through the breakpoints.

Tip You need one launch configuration per function. Add a new node launch object for each function and update the name, args, and environment variables.

Webstorm and Serverless

  1. Create a Node.js configuration and name it _findCharactersByTag_.
  2. In Node parameters: enter node_modules/.bin/sls invoke local -f findCharactersByTag -p examples/findCharactersByTag.json.
  3. Select findCharactersByTag from the configurations select box.
  4. Click the Debug button.
  5. Use the debugger buttons to step through the breakpoints.

AWS SAM Local

Another option for executing Lamdba’s locally is AWS SAM Local. Introduced prior to the 2017 re:Invent, SAM Local built upon the AWS Serverless Application Model (SAM) and is currently in beta.

SAM Local is a CLI tool installed via NPM and requires docker installed and running. SAM requires a template.yml to understand how to run your function. I used Serverless SAM to convert my serverless.yml into a template.yml, but you can also follow the samples in the AWS SAM Local repo to create a template from scratch.

To run SAM Local with debugging execute the following command, where -e is the path to the example request and -d is the debug port.

sam local invoke -e examples/findCharactersByTag.json -d 9229

Make sure to detach your debugger to send the result back to SAM Local.

Visual Studio Code and SAM Local

Open the Debug panel and create a new Node.js launch configuration and add the following to the launch.json:

To begin debugging, set some breakpoints and perform the following steps:

  1. In a terminal run sam local invoke -e examples/findCharactersByTag.json -d 9229.
  2. Select Attach to SAM Local from the configurations select box.
  3. Click the Start Debugging button.
  4. Use the debugger buttons to step through the breakpoints.
  5. Detach the debugger to see the results returned to SAM Local.

Webstorm and SAM Local

  1. In a terminal run sam local invoke -e examples/findCharactersByTag.json -d 9229.
  2. Create an Attach to Node.js/Chrome configuration and name it Attach to SAM Local.
  3. Make sure the port in the configurations matches used in the command line -d parameter.
  4. Select Attach to SAM Local from the configurations select box.
  5. Click the Debug button.
  6. Use the debugger buttons to step through the breakpoints.
  7. Detach the debugger to see the results returned to SAM Local.

You are now equipped with two methods of debugging Lambdas while still using managed services like DynamoDB. Go confidently write your next serverless application!

email

Interested in working with Russell? Schedule a tech call.

2 Comments. Leave new

Thanks for this article. However the SAM Local part doesn’t work. In launch.json “protocol” should be “legacy” instead of “inspector” since the node version is 6.

Reply

Again thanks for the article.
Learnt something more about setting up configurations in “launch.json” for debugging with SAM local, and would like to share to other readers here:
(1) the “protocol” can be “auto”, so no need to decide between “inspector” and “legacy”
(2) for SAM local to work, I have to change the “codeUri” line in template.yml to “CodeUri: .”
(3) the “localRoot” in “launch.json” needs to match the “codeUri” in template.yml. Since here the codeUri is “.”, “${workspaceRoor}” will work. Otherwise you need to put , for example, “${workspaceRoot}/src_dir”. If this is not correctly set, breakpoint in your code won’t work. See https://stackoverflow.com/questions/50684054/visual-studio-code-debugger-not-stopping-at-breakpoints-in-sam-local

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *