Skip to content

Local Gateway Mode - #30

Open
scartill wants to merge 27 commits into
mainfrom
local-mode
Open

Local Gateway Mode#30
scartill wants to merge 27 commits into
mainfrom
local-mode

Conversation

@scartill

@scartill scartill commented Jul 25, 2026

Copy link
Copy Markdown
Owner

No description provided.

This document outlines the design concepts and trade-offs for implementing a local execution mode in EasySAM, allowing developers to run and test Lambda handlers locally against real cloud resources without full deployment.

Original branch: local-mode
Updated the brainstorm document with concrete design decisions for the local lambda execution feature, including the choice of HTTP API, FastAPI, and environment variable resolution strategies.

Original branch: local-mode
Add decisions regarding import strategy and common module resolution to the local lambda execution brainstorm document.

Original branch: local-mode
…fixes

This commit updates the Local Lambda Execution Mode specification to address critical technical risks identified during the critique process. Key changes include:

- Added Req 12: Support for async Lambda handlers.
- Added Req 13: Thread-safe environment variable management using asyncio.Lock.
- Added Req 14: API Gateway v2 response normalization (auto-wrapping, base64 decoding, and 500 error handling).
- Added Req 15: Selective module invalidation to preserve third-party dependencies while allowing hot-reloading of local project code.
- Updated Task 2, 5, and 7 to reflect these requirements, including support for inline JSON strings in local invoke and structured request logging.

Original branch: local-mode
This commit updates the local lambda execution specification to address critical architectural and developer experience findings identified during the critique phase.

Key changes include:
- Added requirements for async handler support, thread-safe environment variable management using asyncio.Lock, and API Gateway v2 response normalization.
- Refined the handler isolation strategy to perform selective module purging, ensuring third-party dependencies (like boto3) remain cached while local project code is reloaded.
- Updated task definitions to include route sorting (to prevent greedy route shadowing), structured request logging, and flexible CLI event input (supporting both file paths and inline JSON).
- Updated the implementation guidance for `load_and_invoke` to handle coroutines and `local_server.py` to include response translation and execution duration tracking.

Original branch: local-mode
Updated the local lambda execution specification to include support for both API Gateway REST API (v1) and HTTP API (v2) event formats. Added details regarding the new `--event-format` CLI option and the `--auth-context` injection mechanism for local authorization stubbing.

Original branch: local-mode
- Update architecture diagram to reflect v1/v2 event synthesis.
- Refine isolated import context to purge all local modules regardless of pre-existing state.
- Wrap environment variable mutation and handler invocation in try...finally blocks to ensure lock release and envvar restoration.
- Specify use of multi_items() for REST API v1 query parameter parsing.
- Update local invoke output to use json.dumps with default=str for robust serialization.

Original branch: local-mode
Added a comprehensive set of task specifications for implementing the local Lambda execution feature, including dependency management, handler isolation, event building, routing, server orchestration, and CLI integration.

Original branch: local-mode
This commit introduces the local command to the EasySAM CLI, allowing users to run SAM templates locally.

Original branch: local-mode
- Added `local_cli.py` for `easysam local` commands (server and invoke).
- Added `local_server.py` using FastAPI to mock API Gateway routing.
- Added `local_event.py` to generate v1 (REST) and v2 (HTTP) API Gateway events.
- Added `local_handler.py` for isolated Lambda function loading and invocation.
- Added `local_routes.py` to map resource definitions to HTTP routes.
- Added comprehensive tests for event generation, handler isolation, and server routing.

Original branch: local-mode
@scartill
scartill marked this pull request as ready for review August 4, 2026 15:13
@scartill
scartill requested a review from janmuhin August 4, 2026 15:13
@scartill

scartill commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Code Review Summary

Decision: REQUEST CHANGES (2 High, 2 Medium findings)

Full report saved to docs/codereviews/pr-30-review.md

Required Fixes:

  1. Path parameter corruption on non-greedy routes (local_server.py): Restrict path_params.pop('path') to greedy catch-all routes (if route.is_greedy and 'path' in path_params:).
  2. Unhandled OSError on Windows (local_cli.py): Wrap Path(value).exists() in ry...except (OSError, ValueError) when parsing --auth-context / --event inline JSON strings.
  3. Cross-platform module cleanup (local_handler.py): Resolve module path with Path(mod_file).resolve() before checking startswith.
  4. Lock contention on request body (local_server.py): Move �wait build_event(...) and
    equest.body() reading before �sync with _invocation_lock:.

Add documentation for the new local execution features, including the `local` server and `local invoke` commands, to the main README and CLI reference.

Original branch: local-mode
Removed the from __future__ import annotations import statement from multiple source files as it is no longer required for the current project configuration.

Original branch: local-mode
- Add error handling for Path instantiation in local_cli to prevent crashes on invalid paths (e.g., Windows-specific characters).
- Resolve module paths before checking against project root in local_handler to ensure accurate stale module detection.
- Refactor local_server to build the event outside the invocation lock and clean up route handler naming logic.
- Remove unused imports across various files.

Original branch: local-mode
Removed unused variables in test files to clean up the codebase and resolve linting warnings.

Original branch: local-mode
- Refactor the code review prompt to improve structure, clarity, and actionable steps for the review process.
- Update the skill hash in skills-lock.json to reflect the changes in the prompt files.

Original branch: local-mode
@scartill

scartill commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

🚀 PR Review (Pass 2): Local Gateway Mode

Summary

This second review pass approves PR #30 (Local Gateway Mode). All 4 High/Medium issues identified in Pass 1 have been completely resolved, validated against test suites, and verified on Windows environment.

The "Why" & "What"

Provides local Lambda execution capability (easysam local . and easysam local invoke <function>) powered by FastAPI, enabling developers to locally run, test, and debug EasySAM applications with full API Gateway v1/v2 event mapping, per-function environment variable isolation, and function URL simulation without requiring cloud deployments.

Key Changes & Improvements in Pass 2

  • Path Parameter Routing Fix: Non-greedy routes with {path} parameters retain exact parameter names, while greedy catch-all routes correctly translate {path} to proxy.
  • Cross-Platform Resilience: Trapped OSError on Windows when parsing inline --auth-context or --event JSON strings.
  • Robust Module Sandbox: Standardized module path matching using Path(...).resolve() to ensure clean unloading of local modules across handler invocations.
  • Concurrency Optimization: Moved network request body reads outside global invocation lock (_invocation_lock) to prevent slow upload streams from blocking concurrent requests.
  • Code Quality: Resolved all ruff linter issues (0 warnings/errors remaining).

QA & Testing Verification

  • Unit & Integration Suite: 74/74 tests passing (uv run pytest tests/).
  • Linter: 0 issues (uv run ruff check).

Recommended Next Action

Approved for Merge into main.

scartill and others added 10 commits August 4, 2026 20:42
Add the second pass code review document for the local-mode implementation, detailing the resolution of functional defects, architectural design, and test validation.

Original branch: local-mode
Consolidate the local server startup logic into a facade function within local_server.py to improve maintainability and allow for programmatic access to the local server functionality. Updated local_cli.py to utilize this new facade.

Original branch: local-mode
Co-authored-by: scartill <1055918+scartill@users.noreply.github.com>
🔍 Scrutineer: Fix broken pip and SAM CLI version checks
Changed the directory option to a positional argument in the local CLI command to improve usability and align with standard CLI patterns.

Original branch: local-mode
Wrap synchronous handler execution in an executor to prevent blocking the main event loop during local invocation. This ensures that synchronous functions do not stall the local runtime environment.

Original branch: local-mode
This change ensures that the local execution environment correctly respects the AWS profile and target region specified in the deployment context. It injects these values into the environment variables (AWS_PROFILE and AWS_DEFAULT_REGION) if they are not already present, ensuring consistent behavior between local invocation and server mode.

Original branch: local-mode
Updated CLI options to support environment variables for configuration. Added documentation to README and CLI_REFERENCE.md to reflect these changes and clarify precedence rules.

Original branch: local-mode
- Load .env files early in the CLI entry point to ensure EASYSAM_* variables are available for Click defaults.
- Update local server environment injection to prioritize EASYSAM environment variables and use setdefault for AWS configuration.
- Add logging for AWS region and profile configuration in local mode.

Original branch: local-mode
@scartill

Copy link
Copy Markdown
Owner Author

Local Gateway & Execution Mode (Pass 3 Final Review)

The "Why" & "What"

EasySAM now supports comprehensive local development and offline testing of SAM applications without needing AWS deployment. This PR adds a local HTTP gateway server (�asysam local .) that mocks AWS API Gateway (v1 REST API and v2 HTTP API formats) and dynamic Lambda function execution (�asysam local invoke ) with isolated module loading, CORS support, custom event synthesis, and AWS credentials/region injection.

Key User-Facing & Behavioral Changes

  • Positional Directory Syntax: Simplified CLI invocation to �asysam local [DIRECTORY] (defaults to current directory .).
  • AWS Profile & Region Passthrough: Added support for --aws-profile and --target-region (and EASYSAM_AWS_PROFILE / EASYSAM_TARGET_REGION env vars) to automatically inject AWS_PROFILE, AWS_DEFAULT_REGION, and AWS_REGION into local handler environments.
  • Bi-Modal API Gateway Simulation: Supports both v1 (REST API) and v2 (HTTP API) event structures with --event-format v1|v2.
  • Authorizer Context Injection: Allows mock authorization context via --auth-context (JSON string or file path).
  • Synchronous & Asynchronous Handler Execution: Handlers are executed with module isolation and restored environment variables.

Risk Assessment & Migration Notes

  • Non-Breaking: Fully backwards compatible with existing EasySAM projects and templates.
  • Local CORS: Local dev server enables wide-open CORS (*) for local frontend development ease; not used in production SAM deployments.
  • Thread Safety: Process environment variable mutations during handler execution are synchronized with a module-level lock (_invocation_lock).

Testing Hints for QA

  1. Local Server Execution: Run �asysam local --port 3000 --event-format v2 . in a project directory and send HTTP requests to test route dispatching and response formatting.
  2. Direct Function Invocation: Execute �asysam local invoke my_function --event '{"key": "value"}' --aws-profile dev and verify environment variables (AWS_PROFILE, AWS_DEFAULT_REGION) are set correctly during execution.
  3. Module Isolation: Trigger multiple requests across different functions in the same local server instance and verify shared dependencies (e.g. common.*) re-resolve cleanly without cross-function state leakage.

Include the EASYSAM_ENVIRONMENT variable in the template configuration to ensure consistent environment identification across deployments.

Original branch: local-mode
- Add asyncio.set_event_loop(None) in local_handler.py to prevent event loop leakage in thread-pool workers.
- Add missing type annotation for context parameter in load_and_invoke.
- Ensure consistent AWS_REGION and AWS_DEFAULT_REGION injection in local_cli.py.
- Reformat long lines in cli.py and local_cli.py to comply with E501 linting rules.

Original branch: local-mode
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant