Skip to content

perf(parser): lazy-load envelopes to reduce Lambda cold start latency by ~900ms - #8405

Merged
leandrodamascena merged 7 commits into
aws-powertools:developfrom
ErezMizrahi:perf/parser-lazy-envelope-imports
Sep 14, 2026
Merged

leandrodamascena merged 7 commits into
aws-powertools:developfrom
ErezMizrahi:perf/parser-lazy-envelope-imports

Conversation

@ErezMizrahi

@ErezMizrahi ErezMizrahi commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Issue number: closes #8406

Summary

Changes

  • Replace eager imports of envelopes and BaseEnvelope in parser/__init__.py with a module-level __getattr__ that defers loading until those names are actually accessed
  • Add a functional test asserting that importing parse does not load any envelope modules

User experience

Before: Any Lambda function importing parse or event_parser from aws_lambda_powertools.utilities.parser caused all 16 envelope modules to load eagerly at cold start — even when no envelope was ever used.

After: Envelope modules are only imported on first access (e.g. when passing envelope=SqsEnvelope to parse()). Functions that use parse() without an envelope pay zero envelope-loading cost.

Measured impact: ~900ms reduction in Lambda INIT_DURATION for API Gateway handlers using parse() without an envelope. Profiled using PYTHONPROFILEIMPORTTIME=1 on AWS Lambda (arm64, Python 3.13, 1024MB):

# Before
import time:  30627 |   1413849 | aws_lambda_powertools.utilities.parser
import time:   6263 |    295176 |   aws_lambda_powertools.utilities.parser.envelopes
# ... 14 more envelope modules loaded unnecessarily

# After
import time:    312 |     41203 | aws_lambda_powertools.utilities.parser
# No envelope modules loaded

Public API is fully preservedfrom aws_lambda_powertools.utilities.parser import envelopes and from aws_lambda_powertools.utilities.parser import BaseEnvelope continue to work exactly as before.


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

…rt latency

Importing `parse` or `event_parser` from `aws_lambda_powertools.utilities.parser`
previously caused all 16 envelope modules to load eagerly via the package
`__init__.py`, even when no envelope was used.

This added ~900ms to Lambda cold start for any function using the parser
without an envelope (the common case for API Gateway handlers).

The fix uses Python's module-level `__getattr__` to defer loading of
`envelopes` and `BaseEnvelope` until they are actually accessed. Public
API is unchanged — existing code importing from this module continues to
work without modification.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@ErezMizrahi
ErezMizrahi requested a review from a team as a code owner August 27, 2026 15:59
@boring-cyborg

boring-cyborg Bot commented Aug 27, 2026

Copy link
Copy Markdown

Thanks a lot for your first contribution! Please check out our contributing guidelines and don't hesitate to ask whatever you need.
In the meantime, check out the #python channel on our Powertools for AWS Lambda Discord: Invite link

@leandrodamascena leandrodamascena left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. The lazy-loading direction is valuable, but the current implementation breaks an existing public import path. I am requesting changes so we preserve compatibility and make the import test reliably isolated.

Comment thread aws_lambda_powertools/utilities/parser/__init__.py Outdated
Comment thread tests/functional/parser/test_parser.py Outdated
ErezMizrahi and others added 2 commits September 6, 2026 06:50
…ests

- Fix RecursionError by using importlib.import_module() and caching in globals()
- Improve test isolation by running tests in fresh subprocesses
- Add tests for all public import paths (parse, envelopes, BaseEnvelope, import *)
- Ensure backward compatibility for all existing public APIs

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Sep 7, 2026
@ErezMizrahi

Copy link
Copy Markdown
Contributor Author

Hi @leandrodamascena,

Thank you for the thorough review and valuable feedback! I've addressed all your comments:

Fixed RecursionError: Now using importlib.import_module() with globals() caching as you suggested
Improved test isolation: All tests now run in fresh subprocesses to ensure reliable isolation
Comprehensive test coverage: Added tests for all public import paths:

  • from parser import parse (should NOT load envelopes)
  • from parser import envelopes (should load envelopes)
  • from parser import BaseEnvelope (should load envelopes)
  • from parser import * (should work correctly)

All tests pass and the lazy-loading behavior is fully preserved while maintaining backward compatibility.

Thanks again for taking the time to review this! 🙏

@codecov

codecov Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 56.25000% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.60%. Comparing base (3e7f852) to head (3938cbf).

Files with missing lines Patch % Lines
aws_lambda_powertools/utilities/parser/__init__.py 56.25% 5 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #8405      +/-   ##
===========================================
- Coverage    96.65%   96.60%   -0.05%     
===========================================
  Files          296      296              
  Lines        14806    14820      +14     
  Branches      1255     1257       +2     
===========================================
+ Hits         14310    14317       +7     
- Misses         361      366       +5     
- Partials       135      137       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@leandrodamascena leandrodamascena left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, Erez. This was really good work.

I ran the benchmark myself using real Lambda functions and confirmed the improvement. On Python 3.13 ARM64, the median Init Duration dropped from 786.65 ms to 553.04 ms across 20 cold starts per variant. The exact number depends on the environment, but the improvement is clear.

I noticed one small compatibility gap: the lazy exports were missing from dir(parser) and inspect.getmembers(parser). I added __dir__ and a regression test directly to your branch. This keeps the envelopes lazy while preserving normal Python introspection.

I am approving this and will merge it once CI is green. Really nice contribution.

@leandrodamascena
leandrodamascena force-pushed the perf/parser-lazy-envelope-imports branch from d3890ce to 6ac623c Compare September 14, 2026 11:31
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Sep 14, 2026
@sonarqubecloud

Copy link
Copy Markdown

@leandrodamascena
leandrodamascena merged commit 51c89a3 into aws-powertools:develop Sep 14, 2026
13 of 15 checks passed
@boring-cyborg

boring-cyborg Bot commented Sep 14, 2026

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request and thank you for helping improve everyone's experience!

@powertools-for-aws-oss-automation

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request and thank you for helping improve everyone's experience!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Denotes a PR that changes 30-99 lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(parser): eagerly loading all 16 envelopes on import adds ~900ms Lambda cold start latency

2 participants