Skip to content

Review Lambda version handling; default num_retained_versions to 5 #1453

@monkut

Description

@monkut

Summary

Review zappa's Lambda function version handling and change the default value of num_retained_versions from null (keep all) to 5. Unbounded retention silently accrues storage cost, and the cost is materially higher when SnapStart is enabled because a cached snapshot is stored per published version.

Current Behavior

  • num_retained_versions is read from zappa_settings.json (zappa/cli.py:2674) and defaults to None — meaning every published version is kept indefinitely.
  • The prune step only runs during zappa update via update_lambda_function(..., num_revisions=...) (zappa/core.py:1296-1379), and is a no-op when num_retained_versions is unset.
  • SnapStart publishes an additional version on every update to create the snapshot (zappa/core.py:1463-1470), so SnapStart users accumulate versions (and snapshots) twice as fast.
  • $LATEST is already excluded from pruning (zappa/core.py:1372).

The net effect: most users never configure num_retained_versions, so historical versions — and their deployment packages and (if enabled) SnapStart snapshots — pile up in the account and show up on the AWS bill with no corresponding operational benefit.

Cost Motivation

Keeping all historical versions costs money on two axes:

  1. Lambda code storage — every published version counts against the account's Lambda code storage quota (default 75 GB per region). Zip packages in this project are typically 50–70 MB each (see the many origzappa-*.zip artifacts in the repo root), so 100 retained versions ≈ 5–7 GB per function.
  2. SnapStart cached snapshots — when SnapStart is enabled, AWS stores a cached snapshot per published version and bills $0.0000015 per GB-second for snapshot cache storage (plus per-restore charges). Snapshots are considerably larger than the deployment package (the runtime + initialized memory image), so per-version snapshot cost dominates code-storage cost, and it is charged continuously for the lifetime of the version.

Rollback, the main reason to retain old versions, rarely needs more than a handful; zappa rollback -n <num> defaults to 1 (zappa/cli.py:376-382). A small bounded default captures the rollback use case without unbounded spend.

Proposal

Change the default value of num_retained_versions from None to 5.

  • None/null continues to mean "keep all" (explicit opt-out).
  • Any positive integer continues to mean "keep the latest N".
  • Default of 5 is enough for practical rollback while bounding storage and SnapStart snapshot cost.

Implementation

  • Change the default at zappa/cli.py:2674 from None to 5.
  • Update the validation message at zappa/cli.py:2677-2683 to reflect the new default.
  • Update README / docs to document the new default and how to opt out (num_retained_versions: null).
  • Add a CHANGELOG entry flagging the behavior change — on first zappa update after upgrade, users with many retained versions will see older versions pruned.
  • Consider logging the list of versions being deleted (and counts) so the behavior change is visible in deploy output.

Backwards-Compatibility Note

This is a behavior change on upgrade: the next zappa update will prune any versions older than the newest 5 for users who relied on the implicit "keep all" default. Alias-guarded and \$LATEST versions remain safe; other versions referenced by aliases currently still raise ResourceConflictException (see #960), which is a pre-existing concern that this change makes more likely to surface. Fixing #960 alongside this default change would make the upgrade smoother.

Acceptance Criteria

  • Default of num_retained_versions is 5.
  • Add num_retained_versions to default created zappa_settings.json
  • Setting num_retained_versions: null disables pruning (keep all).
  • README/docs updated to describe the new default and the cost rationale (including SnapStart snapshot storage).
  • CHANGELOG entry added noting the behavior change.
  • Tests updated / added to cover the new default.

References

  • zappa/cli.py:2674-2683num_retained_versions parsing and validation
  • zappa/core.py:1296-1379update_lambda_function pruning logic
  • zappa/core.py:1463-1470 — SnapStart extra-version publish on update
  • zappa/core.py:1576-1584get_lambda_function_versions
  • Related: Retained versions and alias #960 (alias-reference deletion conflict — likely surfaces more often once pruning is on by default)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions