Skip to content

Commit

Permalink
feat!: add the AWS Lambda environment variables and allow to overload…
Browse files Browse the repository at this point in the history
… them in config

BREAKING CHANGE: to allow access to more context, the event generator functions now take the the Starlette.Request, a SmythHandler instance and a RunnerProcessProtocol compatible type. Previously there was only the request
  • Loading branch information
pkucmus committed Dec 28, 2024
1 parent 70628dc commit cbd6add
Show file tree
Hide file tree
Showing 23 changed files with 465 additions and 144 deletions.
162 changes: 152 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
Expand All @@ -12,20 +19,155 @@ lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

.ruff_cache/
__pycache__
# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock

.DS_Store
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.pytest_cache
.python-version
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

package
*.zip
.mypy_cache
.coverage
# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# PyPI configuration file
.pypirc

.ruff_cache/
36 changes: 18 additions & 18 deletions docs/user_guide/all_settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ Here's a list of all the settings, including those that are simpler but equally

## Smyth Settings

### Host
### Socket Binding

`host` - `str` (default: `"0.0.0.0"`) Used by Uvicorn to bind to an address.

### Port

`port` - `int` (default: `8080`) Used by Uvicorn as the bind port.

### Log Level
### Logging

`log_level` - `str` (default: `"INFO"`) Sets the logging level for the `uvicorn` and `smyth` logging handlers.

### Smyth Path Prefix
### Smyth Internals

`smyth_path_prefix` - `str` (default: `"/smyth"`) The path prefix used for Smyth's status endpoint. Change this if, for any reason, it collides with your path routing.

### Environment

`env` - `dict[str, str]` (default: `{}`) Environment variables to apply to every handler. Read more about [environment variables here](environment.md).

## Handler Settings

### Handler Path
Expand All @@ -28,32 +30,30 @@ Here's a list of all the settings, including those that are simpler but equally

### URL Path

`url_path` - `str` (required) The Starlette routing path on which your handler will be exposed.
`url_path` - `str` (required) The [Starlette routing](https://www.starlette.io/routing/#http-routing) path on which your handler will be exposed.

### Timeout
### Environment

`timeout` - `float` (default: `None`, which means no timeout) The time in seconds after which the Lambda Handler raises a Timeout Exception, simulating Lambda's real-life timeouts.
`env` - `dict[str, str]` (default: `{}`) Environment variables to apply to this handler - keys defined here take precedence over the ones defined in `tool.smyth.env` and be otherwise merged. Read more about [environment variables here](environment.md).

### Event Data Function
### Customization

`event_data_function_path` - `str` (default: `"smyth.event.generate_api_gw_v2_event_data"`) Read more about [event functions here](event_functions.md).

### Context Data Function

`context_data_function_path` - `str` (default: `"smyth.context.generate_context_data"`) A function similar to the [event generator](event_functions.md), but it constructs the `context`, adding some metadata from Smyth's runtime. You can create and use your own.

### Log Level

`log_level` - `str` (default: `"INFO"`) Log level for Smyth's runner function, which is still part of Smyth but already running in the subprocess. Note that the logging of your Lambda handler code should be set separately.
### Behaviour

### Concurrency
`timeout` - `float` (default: `None`, which means no timeout) The time in seconds after which the Lambda Handler raises a Timeout Exception, simulating Lambda's real-life timeouts.

`concurrency` - `int` (default: `1`) Read more about [concurrency here](concurrency.md).

### Strategy Generator

`strategy_generator_path` - `str` (default: `"smyth.runner.strategy.first_warm"`) Read more about [dispatch strategies here](concurrency.md/#dispatch-strategy).

### Logging

`log_level` - `str` (default: `"INFO"`) Log level for Smyth's runner function, which is still part of Smyth but already running in the subprocess. Note that the logging of your Lambda handler code should be set separately.


## `pyproject.toml` example

Expand All @@ -65,7 +65,7 @@ log_level = "INFO"
smyth_path_prefix = "/smyth"

[tool.smyth.handlers.lambda_handler]
handler_path = "nimara_search_algolia_backend.app.lambda_handler"
handler_path = "myproject.app.lambda_handler"
url_path = "{path:path}"
timeout = 300
event_data_function_path = "smyth.event.generate_api_gw_v2_event_data"
Expand Down
3 changes: 2 additions & 1 deletion docs/user_guide/custom_entrypoint.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ Here's an example `smyth_conf.py` file:
import uvicorn
from smyth.server.app import SmythStarlette
from smyth.smyth import Smyth
from smyth.types import EventData, RunnerProcessProtocol, SmythHandler
from starlette.requests import Request


def my_handler(event, context):
return {"statusCode": 200, "body": "Hello, World!"}

async def my_event_data_generator(request: Request):
async def my_event_data_generator(request: Request, smyth_handler: SmythHandler, process: RunnerProcessProtocol) -> EventData:
return {
"requestContext": {
"http": {
Expand Down
61 changes: 61 additions & 0 deletions docs/user_guide/environment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Environment

Smyth allows you to overwrite the environemnt variables that are passed to the handlers to better reflect the actual AWS Lambda environment while allowing you to change things while developing locally.


```toml title='pyproject.toml' linenums="1"
[tool.smyth]
host = "0.0.0.0"
port = 8080
...

[tool.smyth.env]
AWS_ENDPOINT = "http://localstack:4566"
AWS_LAMBDA_FUNCTION_VERSION = "$SMYTH"

[tool.smyth.handlers.my_special_version_handler]
handler_path = "mypyoject.app.my_special_version_handler"
url_path = "{path:path}"
...

[tool.smyth.handlers.my_special_version_handler.env]
AWS_LAMBDA_FUNCTION_VERSION = "34"
```

The config above allows you to set a specific env var for every defined handler and overwrite or set
specific values for individual handlers. In the example every handler would receive the
`AWS_ENDPOINT = "http://localstack:4566"` and `AWS_LAMBDA_FUNCTION_VERSION = "$SMYTH"` env vars with
the exception of `my_special_version_handler` which will have a different version.

## Fake context

The `smyth.runner.fake_context.FakeLambdaContext` class used by Smyth will also consume of of the environment variables.

## Default variables

In the table bellow you will find which keys are set by Smyth when a handler is being invoked.
Smyth will look for the key in the following order:

1. the handler configuration `env` key
2. the smyth global configuration `env` key
3. `os.environ`
4. when none of the above contain the key the default value is assigned

| Key | Default Value |
| ----------------------------------- | ---------------------------------------------------------------------- |
| `"_HANDLER"` | `self.lambda_handler_path` |
| `"AWS_ACCESS_KEY_ID"` | `"000000000000"` |
| `"AWS_SECRET_ACCESS_KEY"` | `"test"` |
| `"AWS_SESSION_TOKEN"` | `"test"` |
| `"AWS_DEFAULT_REGION"` | `"eu-central-1"` |
| `"AWS_REGION"` | `"eu-central-1"` |
| `"AWS_EXECUTION_ENV"` | `"AWS_Lambda_python{sys.version_info.major}.{sys.version_info.minor}"` |
| `"AWS_LAMBDA_FUNCTION_MEMORY_SIZE"` | `"128"` |
| `"AWS_LAMBDA_FUNCTION_NAME"` | `self.name` |
| `"AWS_LAMBDA_FUNCTION_VERSION"` | `"$LATEST"` |
| `"AWS_LAMBDA_INITIALIZATION_TYPE"` | `"on-demand"` |
| `"AWS_LAMBDA_LOG_GROUP_NAME"` | `"/aws/lambda/{self.name}"` |
| `"AWS_LAMBDA_LOG_STREAM_NAME"` | `"{strftime('%Y/%m/%d')}/[$LATEST]smyth_aws_lambda_log_stream_name"` |
| `"AWS_LAMBDA_RUNTIME_API"` | `"127.0.0.1:9001"` |
| `"AWS_XRAY_CONTEXT_MISSING"` | `"LOG_ERROR"` |
| `"AWS_XRAY_DAEMON_ADDRESS"` | `"127.0.0.1:2000"` |
5 changes: 4 additions & 1 deletion docs/user_guide/event_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ The first one builds a minimal API Gateway Proxy V2 event to simulate a Lambda b
If you need to work with events not covered by Smyth, you can create and provide your own. Assuming a simplified API Gateway V1 event, you can create a generator like this:

```python title="my_project/src/smyth_utils/event.py" linenums="1"
async def generate_api_gw_v1_event_data(request: Request):
from smyth.types import EventData, RunnerProcessProtocol, SmythHandler


async def generate_api_gw_v1_event_data(request: Request, smyth_handler: SmythHandler, process: RunnerProcessProtocol) -> EventData:
source_ip = None
if request.client:
source_ip = request.client.host
Expand Down
2 changes: 1 addition & 1 deletion docs/user_guide/index.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# User Guide
# First Steps

Smyth is built to have minimal or no impact on the project you are working on. That said, it comes with features that allow you to customize Smyth to the needs of your Lambda project.

Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ theme:
- content.code.copy
- content.code.annotate
- content.tabs.link
- navigation.indexes
- navigation.footer
- navigation.tracking
- navigation.expand
Expand All @@ -31,6 +30,7 @@ nav:
- user_guide/event_functions.md
- user_guide/invoke.md
- user_guide/concurrency.md
- user_guide/environment.md
- user_guide/all_settings.md
- user_guide/custom_entrypoint.md
- user_guide/non_http.md
Expand Down
Loading

0 comments on commit cbd6add

Please sign in to comment.