I wrote a tool, AWS Lambda Persistence, which is a Python module that enables AWS Lambda functions to maintain state and persist data between invocations by writing to a dict-like variable. It achieves this by using the DynamoDB free tier and so it can be used without adding any costs to your project.
https://github.com/gene1wood/aws-lambda-persistence
The [README gives details on how to use it in AWS Lambda](https://github.com/gene1wood/aws-lambda-persistence?tab=readme-ov-file#how-to-install-it).
Here's an example of what the AWS Lambda code would look like using the tool. This example uses the built-in AWS Lambda cache, and backs it with PersistentMap for when the cache is lost.
```python
import datetime
from aws_lambda_persistence import PersistentMap
def lambda_handler(event, context):
global data
if 'data' not in globals():
# data isn't present in Lambda cache already
data = PersistentMap()
if 'expiration_datetime' in data:
if data['expiration_datetime'] < datetime.datetime.now():
data.update({
'special_value': expensive_function(event),
'expiration_datetime': datetime.datetime.now() + datetime.timedelta(hours=4)
})
```
And here's an example with a complete CloudFormation template
```yaml
AWSTemplateFormatVersion: '2010-09-09'
Resources:
ExampleFunction:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
import datetime
from aws_lambda_persistence import PersistentMap
def lambda_handler(event, context):
global data
if 'data' not in globals():
data = PersistentMap()
result = ("The persistent data wasn't in the Lambda cache so "
"it was pulled from DynamoDB. ")
else:
result = "The persistent data was pulled from Lambda cache. "
if 'last_run' in data:
result += f"This function was last run at {data['last_run']}"
else:
result += f"This is the first time the function has run."
data['last_run'] = datetime.datetime.now()
return(result)
Handler: index.lambda_handler
Layers:
- arn:aws:lambda:us-west-2:220481034027:layer:aws-lambda-persistence:2
PackageType: Zip
Role: !GetAtt ExampleRole.Arn
Runtime: python3.14
# On first run, if the DynamoDB doesn't exist, execution can take 11+ seconds
# Clod starts with a pull from DynamoDB can take 4+ seconds
Timeout: 30
ExampleRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: AllowPersistentMap
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:CreateTable
- dynamodb:TagResource
- dynamodb:PutItem
- dynamodb:DescribeTable
- dynamodb:GetItem
Resource: arn:aws:dynamodb:*:*:table/AWSLambdaPersistence
```
I wrote a tool, AWS Lambda Persistence, which is a Python module that enables AWS Lambda functions to maintain state and persist data between invocations by writing to a dict-like variable. It achieves this by using the DynamoDB free tier and so it can be used without adding any costs to your project.
https://github.com/gene1wood/aws-lambda-persistence
The [README gives details on how to use it in AWS Lambda](https://github.com/gene1wood/aws-lambda-persistence?tab=readme-ov-file#how-to-install-it).
Here's an example of what the AWS Lambda code would look like using the tool. This example uses the built-in AWS Lambda cache, and backs it with PersistentMap for when the cache is lost.
```python
import datetime
from aws_lambda_persistence import PersistentMap
def lambda_handler(event, context):
global data
if 'data' not in globals():
# data isn't present in Lambda cache already
data = PersistentMap()
if 'expiration_datetime' in data:
if data['expiration_datetime'] < datetime.datetime.now():
data.update({
'special_value': expensive_function(event),
'expiration_datetime': datetime.datetime.now() + datetime.timedelta(hours=4)
})
```
And here's an example with a complete CloudFormation template
```yaml
AWSTemplateFormatVersion: '2010-09-09'
Resources:
ExampleFunction:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
import datetime
from aws_lambda_persistence import PersistentMap
def lambda_handler(event, context):
global data
if 'data' not in globals():
data = PersistentMap()
result = ("The persistent data wasn't in the Lambda cache so "
"it was pulled from DynamoDB. ")
else:
result = "The persistent data was pulled from Lambda cache. "
if 'last_run' in data:
result += f"This function was last run at {data['last_run']}"
else:
result += f"This is the first time the function has run."
data['last_run'] = datetime.datetime.now()
return(result)
Handler: index.lambda_handler
Layers:
- arn:aws:lambda:us-west-2:220481034027:layer:aws-lambda-persistence:2
PackageType: Zip
Role: !GetAtt ExampleRole.Arn
Runtime: python3.14
# On first run, if the DynamoDB doesn't exist, execution can take 11+ seconds
# Clod starts with a pull from DynamoDB can take 4+ seconds
Timeout: 30
ExampleRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: AllowPersistentMap
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:CreateTable
- dynamodb:TagResource
- dynamodb:PutItem
- dynamodb:DescribeTable
- dynamodb:GetItem
Resource: arn:aws:dynamodb:*:*:table/AWSLambdaPersistence
```