aws-sam-cli: sam local start-api doesn't update on changes

Description

I am using the sample hello-world application on nodejs12.x using sam init but when I invoke sam build and sam local start-api any subsequent changes I make to the lambda function don’t update on the port.

Steps to reproduce

sam init
Choice: 1 (AWS Quick Start Templates)
Runtime: 1 (nodejs12.x)
cd sam-app
sam build && sam local start-api

Inside the hello-world/app.js response object I change the message property and save.

Observed result

I refresh 127.0.0.1:3000/hello on the browser and nothing changes.

Expected result

I should see the message updated as per how sam local start-api is meant to work.

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

sam --version SAM CLI, version 0.47.0

docker --version Docker version 19.03.8, build afacb8b

aws --version aws-cli/1.11.80 Python/2.7.10 Darwin/18.7.0 botocore/1.5.43

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 10
  • Comments: 23 (5 by maintainers)

Most upvoted comments

okay but it’s clear this message is causing a lot of confusion. It’s updating something else automatically but not the code. That isn’t immediately obvious.

@rpstreef This isn’t a bug. The log statement predates build so maybe there is an update to the message but everything is working as intended. sam build will produce a template that has the updated built artifacts. sam local start-api reads that template to stand up the endpoint. You still do not need to restart sam local start-api if your code changes but you do need to update the artifacts build produced by running sam build again. Otherwise, the code changes you made are not represented in the built artifacts within .aws-sam/build and will not update in the next invoke of the function.

Apologies, I have dug a little further on this github repository and realize this isn’t possible for now. Kind of a bummer because it is quite annoying as a development experience to have to constantly build after every change.

I believe this is the correct issue for tracking: https://github.com/awslabs/aws-sam-cli/issues/921

For now, anyone coming up here for the same confusion, this is what I’m doing to improve my experience in the interim:

npm i -g nodemon
nodemon --exec sam build

I run this in the root folder of my sam application in one terminal and run sam local start-api in another. This builds on every save so I don’t have to do it manually.

Closing this issue.

Hmmm, I was under the impression that I could work on an existing function without needing to rebuild:

You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template

@jfuss there’s still a lot of explanation required for this feature, in my opinion this is simply due to unclear documentation.

Fix the documentation, and the problem goes away.

@rpstreef What’s your recommendation? Are you interested in submitting a PR with an updated message?

You need to either update your documentation that actually suggests hot reloading of code does work or you need to implement it:

https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-using-start-api.html

That GIF image clearly demonstrates the hot reloading of code changes.

My recommendation is to implement that, or otherwise to just remove the message in the CLI all together.

When looking at this issue, what is reported in the CLI tool You only need to restart SAM CLI if you update your AWS SAM template and what it actually does, does not correspond.

Is there an intention to fix this bug? Or was this never intended to work like this in the first place?

This is confusing indeed, but there is a workaround. If the ./aws-sam/build/ is empty, the source version of the functions are used instead of the built. Note that the first is dynamic and the later is not.

So, instead of bundling my dependencies in the main function, I took a much cleaner approach - bundle my dependencies within a lambda layer. Which should be the first choice in any case.

While running the local api, I simply delete the ./aws-sam/build/ directory and start the api. Here is how my package.json looks like:

  "scripts": {
    ....
    "local:dep:python:lambda":  "rm -rf ./lambdas/layers/venv/python/ && pip install -r requirements.txt -t ./lambdas/layers/venv/python/",
    "sam:start-api": "sam local start-api",
    "local:api": "rm -rf .aws-sam/build/ && npm run local:dep:python:lambda && npm run sam:start-api"
  }

Also the sam template references the layer that corresponds to the package dependencies:

      ....
      Layers:
        - !Ref FunctionAssetsLayer
        - !Ref **FunctionDependenciesLayer**

On a side note, @jfuss I’m new to sam but would like to take this up. I haven’t used it enough to get hang of the access patterns, so can you help me with what would be the ideal way to fix this ?

for development purposes wouldn’t it be possible to have an option to keep a local docker volume mount that points to a shared folder such as dist/app.js . Then the local system can watch and build using whatever tools needed and the docker image would just need to watch that one file and restart itself if it’s currently warm?

oh wow this is really confusing. What’s the correct development workflow for the following situation:

I’m building a python lambda function, I start playing around with just the default lambda function adding in code and seeing my changes in real time. I then add another python package in which case I need to run sam build for the requirements.txt to be picked up. I then start adding more code to my function but I don’t see any of the changes until I run sam build again.

Should I be using a task runner to sam build every time the function changes? How do you pull in external packages without breaking the really really useful functionality of sam local start-api?

This is confusing indeed, but there is a workaround. If the ./aws-sam/build/ is empty, the source version of the functions are used instead of the built. Note that the first is dynamic and the later is not.

So, instead of bundling my dependencies in the main function, I took a much cleaner approach - bundle my dependencies within a lambda layer. Which should be the first choice in any case.

While running the local api, I simply delete the ./aws-sam/build/ directory and start the api. Here is how my package.json looks like:

  "scripts": {
    ....
    "local:dep:python:lambda":  "rm -rf ./lambdas/layers/venv/python/ && pip install -r requirements.txt -t ./lambdas/layers/venv/python/",
    "sam:start-api": "sam local start-api",
    "local:api": "rm -rf .aws-sam/build/ && npm run local:dep:python:lambda && npm run sam:start-api"
  }

Also the sam template references the layer that corresponds to the package dependencies:

      ....
      Layers:
        - !Ref FunctionAssetsLayer
        - !Ref **FunctionDependenciesLayer**

On a side note, @jfuss I’m new to sam but would like to take this up. I haven’t used it enough to get hang of the access patterns, so can you help me with what would be the ideal way to fix this ?

Is there a workaround for Python?

Is there a workaround for Python?

Same here. Please share if anyone has sorted this.

I wonder how chalice does hot reload. I’m sure this should be implemented for python. Looking forward to a resolution. Thanks.

I can confirm it hot reloads if you don’t have the build folder there.

@fakekamrankhan Did you rebuild after changes? You need to run sam build again for code changes to be reflected.

approach with layers may work for python as well without platform specific wheels in the dependencies:

template.yaml:

  FunctionLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      CompatibleRuntimes: 
        - python3.8
      ContentUri: code/function-layer/.
    Metadata:
      BuildMethod: python3.8

  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: code/function/
      Handler: app.lambda_handler
      Runtime: python3.8
      Layers:
        - !Ref FunctionLayer

install dependencies:

# cd code/function-layer
# pip install -r requirements.txt -t ./python

update and invoke without running sam build:

sam local invoke Function