Working with Lambda Functions in Stelvio
Stelvio provides an easy way to create and configure AWS Lambda functions. In this guide, we'll explore how to organize your Lambda functions and manage their dependencies.
Understanding Lambda Organization
When creating Lambda functions in Stelvio, you have two main approaches for organizing your code:
- Single-file functions
- Folder-based functions
Each approach has its own use cases and benefits.
Single-File Lambda Functions
Single-file functions are perfect for simple, focused tasks that don't require additional code files. Here's how to create one:
# functions/simple.py
def handler(event, context):
return {
"statusCode": 200,
"body": "Hello from Lambda!"
}
# In your infrastructure code
fn = Function(handler="functions/simple.handler")
Key characteristics of single-file functions:
- One Python file contains all the function code
- Cannot import from other files in the same directory
- Perfect for simple, focused tasks
- Automatically packaged by Stelvio
Folder-Based Lambda Functions
For more complex scenarios where you need to split your code across multiple files, use folder-based functions:
# functions/
# └── users/
# ├── handler.py # Main function code
# ├── database.py # Database operations
# └── validation.py # Input validation
# In your infrastructure code
fn = Function(
src="functions/users", # folder of the function
handler="handler.process" # Relative to src directory
)
Key characteristics of folder-based functions:
- Can split code across multiple files
- Can import between files in the folder
- All files in the folder are packaged together
- Perfect for complex functions with shared code
Function Configuration
You can configure your Lambda functions by specifying different parameters to Function class:
from stelvio.aws.function import Function
fn = Function(
src="users", # For folder-based Lambda
handler="handler.process", # Handler function
memory_size=512, # Memory in MB
timeout=30, # Timeout in seconds
)
For simpler cases, when you're happy with defaults, you can just provide the handler:
Linking and Environment Variables
When you link other components to your Lambda function, Stelvio automatically:
- Generates the necessary IAM permissions
- Creates lambda environment variables for component access
- Generates a type-safe component access python file
Here's how it works:
# Create component
from stelvio.aws.dynamo import AttributeType, DynamoTable
from stelvio.aws.function import Function
table = DynamoTable(
name="users",
fields={
"user_id": AttributeType.STRING
},
partition_key="user_id"
)
# Link to Lambda
fn = Function(
handler="users/handler.process",
links=[table] # Link the table to the function
)
Stelvio generates a stlv_resources.py file in your Lambda's directory:
# Generated stlv_resources.py
import os
from dataclasses import dataclass
from typing import Final
@dataclass(frozen=True)
class UsersResource:
@property
def table_arn(self) -> str:
return os.getenv("STLV_USERS_TABLE_ARN")
@property
def table_name(self) -> str:
return os.getenv("STLV_USERS_TABLE_NAME")
@dataclass(frozen=True)
class LinkedResources:
users: Final[UsersResource] = UsersResource()
Resources: Final = LinkedResources()
You can then use these resources in your Lambda code with full IDE support:
from stlv_resources import Resources
def handler(event, context):
table_name = Resources.users.table_name
# Use table_name with boto3...
This provides:
- Type-safe access to resource properties
- IDE completion for available resources
Best Practices
-
Start Simple:
- Use single-file functions for simple tasks
- Move to folder-based organization when your function gets bigger or needs special dependencies.
-
Dependency Management:Keep requirements.txt files focused and minimalUse layers for shared dependenciesLet Stelvio handle platform-specific installations
-
Resource Access:
- Use the generated Resources object for type-safe resource access
- Keep your functions focused on business logic
- Let Stelvio manage IAM permissions through linking
-
Function Organization:
- Keep related code together in folder-based functions
- Use clear file names and structure
Managing Dependencies
NOT IMPLEMENTED
While dependency management is designed in Stelvio it has not been implemented yet. It's one of the top priorities. This section is here for you to know what to expect in the future releases and I'm happy to take any suggestions.
Stelvio automatically handles Python dependencies for your Lambda functions. Let's explore how this works.
Dependencies for Single-File Functions
When you write single-file Lambda functions, Stelvio looks for a requirements.txt file in the same directory as your functions. Here's an example of several single-file functions with their dependencies:
functions/
├── login.py # Handles user login
├── register.py # Handles user registration
├── process_order.py # Processes new orders
└── requirements.txt # Dependencies shared by these functions
Dependencies for Folder-Based Functions
For folder-based functions, place your requirements.txt inside the function folder:
functions/
├── users/
│ ├── handler.py # Main handler with multiple functions
│ ├── database.py # Database operations
│ ├── validation.py # Input validation
│ └── requirements.txt # Dependencies for this Lambda
└── orders/
├── handler.py # Order processing handlers
├── stripe.py # Payment processing
└── requirements.txt # Dependencies for this Lambda
How Dependency Installation Works
When Stelvio packages your Lambda function, it:
- Detects the relevant requirements.txt file
- Downloads dependencies using platform-specific settings for AWS Lambda e.g.:
- Packages the installed dependencies with your function code
This ensures your dependencies work correctly in the Lambda environment.
Sharing Dependencies
You can share common dependencies using pip's -r
flag in your requirements.txt files:
functions/
├── base_requirements.txt # Common dependencies
├── login.py
├── requirements.txt # Can include: -r ../base_requirements.txt
└── orders/
├── handler.py # Order processing handlers
├── stripe.py # Payment processing
└── requirements.txt # Can include: -r ../base_requirements.txt or -r ../requirements.txt
Important Notes
- Stelvio installs all packages listed in
requirements.txt
- it doesn't analyze which imports are actually used - Consider package sizes as they affect your Lambda deployment package size and consequently also lambda cold start.
Stelvio handles all the complexity of dependency installation and packaging automatically, letting you focus on writing your Lambda function code.
Lambda Layers
NOT IMPLEMENTED
Lambda layers suppport is not implemented yet. It's one of the top priorities. This section is here for you to know what to expect in the future releases and I'm happy to take any suggestions.
For sharing code between functions, you can create Lambda layers:
from stelvio.aws.function import Function, Layer
my_layer = Layer(
name="my_layer",
src="layers/utils", # Layer source directory
)
fn = Function(
"my-function",
handler="handler.process",
layers=[my_layer]
)
Each layer is in it's own folder layer directory should follow the following structure:
layers
└── my_layer/
├──my_utils/ # Your code in layer needs its own folder. Then you can impor it like from my_utils.db import something
│ └──db.py
│ └──helpers.py
└──requirements.txt # Layer dependencies
Next Steps
Now that you understand Lambda functions in Stelvio, you might want to explore:
- Working with API Gateway - Learn how to create APIs
- Working with DynamoDB - Learn how to create DynamoDB tables
- Linking - Learn how linking automates IAM, permissions, envars and more
- Project Structure - Discover patterns for organizing your Stelvio applications