Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

FastAPI with Lambda SnapStart (container image)

This example shows how to use the Lambda Web Adapter's SnapStart hooks to drain and re-establish a connection pool around the snapshot/restore boundary, packaged as a container image (OCI) rather than a zip.

For the zip-packaged equivalent, see fastapi-snapstart-zip.

How does it work?

The Dockerfile copies the Lambda Web Adapter binary into /opt/extensions:

FROM public.ecr.aws/docker/library/python:3.12-slim
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:1.1.0 /lambda-adapter /opt/extensions/lambda-adapter
ENV PORT=8000
WORKDIR /var/task
COPY requirements.txt ./
RUN python -m pip install -r requirements.txt
COPY *.py ./
CMD exec uvicorn --port=$PORT main:app

The two SnapStart hook endpoints are configured as function environment variables in template.yaml, keeping the image itself generic:

      Environment:
        Variables:
          AWS_LWA_SNAPSTART_BEFORE_CHECKPOINT_PATH: /snapstart/before
          AWS_LWA_SNAPSTART_AFTER_RESTORE_PATH: /snapstart/after

When the function runs under SnapStart, the adapter calls your application at the snapshot boundary:

  • Before the snapshot — AWS_LWA_SNAPSTART_BEFORE_CHECKPOINT_PATH is set to /snapstart/before. The adapter sends an empty HTTP POST to this path. The app uses it to drain and close resources that will not survive the snapshot (in this example, it closes the connection pool).
  • After restore, before traffic is served, the adapter performs three steps in order:
    1. It refreshes its own HTTP connection to the inner app, so it never reuses a connection captured in the snapshot (this is automatic — you do not configure or manage the adapter's client).
    2. AWS_LWA_SNAPSTART_AFTER_RESTORE_PATH is set to /snapstart/after. The adapter sends an empty HTTP POST to this path over the refreshed connection. The app uses it to re-establish connections and regenerate per-environment unique values (in this example, it reconnects the pool and generates a fresh connection_id).
    3. It re-runs the readiness check against your app before admitting traffic.

Both hook routes must return a 2xx status code. A non-2xx response or a connection failure fails the SnapStart phase. The adapter sets no deadline of its own — but Lambda allows the whole Restore phase only 10 seconds, regardless of the function timeout, and the after-restore hook shares that window with the readiness check that follows it. The readiness check runs on every restore; by default it waits indefinitely for the app to recover, but you can bound it with AWS_LWA_READINESS_CHECK_TIMEOUT_SECONDS (fractional seconds allowed), in which case a restore whose app does not report ready within that timeout fails — so traffic is never served against an app that has not finished recovering. A bound above the 10-second Restore limit cannot take effect; Lambda times the phase out first.

These hook routes are protected on the Lambda invocation path: the 403 guard lives in the adapter, which only sits in front of your app when it is processing Lambda events, so external callers that reach the function via API Gateway or ALB and request /snapstart/before or /snapstart/after receive a 403 Forbidden.

Warning: that guard exists only when the adapter is in the request path. Because the adapter is packaged inside the image, the same container also runs unchanged on Amazon ECS, Amazon EKS, or a local Docker host (docker run -p 8000:8000 below) — but in those deployments traffic goes straight to your app and the guard is not present. /snapstart/before and /snapstart/after are state-mutating (this example closes and re-establishes the connection pool), so outside Lambda you must not expose them publicly, or protect them yourself.

Pre-requisites

Build and Deploy

Build the container image and deploy with SAM:

sam build
sam deploy --guided

When the deployment completes, take note of the FastAPISnapStartApi output — it is the API Gateway endpoint URL.

Verify it works

Open the API URL in a browser or with curl:

curl https://xxxxxxxxxx.execute-api.us-west-2.amazonaws.com/

The response reports the connection state, for example:

{
  "message": "Hello from FastAPI on Lambda SnapStart (container image)",
  "connected": true,
  "connection_id": 426384719
}

After a SnapStart restore, the connection_id is regenerated rather than shared across every restored environment, because the adapter calls the after-restore hook (/snapstart/after), which reconnects the pool and generates a fresh id. This is exactly the behavior you want for any per-environment value (connections, random seeds, unique identifiers) that must not be duplicated across restored snapshots.

Run the container locally

The same image runs locally — without SnapStart, the hooks are simply never invoked:

docker run -d -p 8000:8000 {ECR Image}
curl localhost:8000/