Reputation: 8312
Description
I have AWS CloudWatch Events set up to invoke a Lambda function every 5 minutes.
What I would like to achieve is to monitor whether the response of an API has changed. Therefore I would like to pass the result of the previous invocation on to the next invocation, for comparison.
The result is an array of < 200 elements and therefore quite small.
My considerations are:
Both options seems like a lot of gunpowder to use for shooting a few pigeons, so my question is:
Is there a simpler way to pass results between invocations of Lambda functions?
Upvotes: 0
Views: 617
Reputation: 8312
I allow myself to also add an answer, based on @Marcin's comment on utilising the AWS System Manager parameter store, as it solves my question and tackles the request of a lightweight solution.
Here's an example of a counter, incremented each time a Lambda function is invoked:
// handler.js, Lambda entry point
const AWS = require('aws-sdk')
const ssm = new AWS.SSM();
const SSM_KEY = 'SSMData';
const getSSMData = async () => {
var getParams = {
Name: SSM_KEY,
};
try {
const data = await new Promise((resolve, reject) => {
ssm.getParameter(getParams, (error, data) => {
if (error) reject(error)
if (data) resolve(data)
});
});
if (data.Parameter && data.Parameter.Value) {
return JSON.parse(data.Parameter.Value)
} else {
return null
}
} catch (error) {
return false
}
}
const putSSMData = async (data) => {
const jsonData = JSON.stringify(data)
var putParams = {
DataType: "text",
Name: SSM_KEY, /* required */
Type: 'String',
Value: jsonData, /* Max 4kb */
Overwrite: true
};
try {
await new Promise((resolve, reject) => {
ssm.putParameter(putParams, (error, data) => {
if (error) reject(error)
if (data) resolve(data)
});
});
return true
} catch (error) {
console.log(error, error.stack);
return false;
}
};
module.exports.hello = async (event, context) => {
let previousResult = await getSSMData()
if (!previousResult) {
previousResult = {
count: 0
}
}
console.log({ previousResult })
const nextResult = { ...previousResult, count: previousResult.count + 1 }
await putSSMData(nextResult)
};
Result
Lambda invokation 1: { previousResult: { count: 0 } }
Lambda invokation 2: { previousResult: { count: 1 } }
Lambda invokation 3: { previousResult: { count: 2 } }
...
Permissions
It is necessary to add an IAM role for the Lambda function to use SSM. Using the serverless framework:
iamRoleStatements:
- Effect: "Allow"
Action:
- "ssm:GetParameter"
Resource:
- "arn:aws:ssm:<REGION>:<ACCOUNT_ID>:parameter/SSMData"
- Effect: "Allow"
Action:
- "ssm:PutParameter"
Resource:
- "arn:aws:ssm:<REGION>:<ACCOUNT_ID>:parameter/SSMData"
Upvotes: 1
Reputation: 51634
You’re right, EFS would probably be too much of an overhead.
However, Amazon S3 and DynamoDB both are perfectly suitable to persist data between individual invocations of a Lambda function.
The Lambda service itself doesn’t provide long-term persistence out of the box. It is better to architect functions in a stateless way and use serverless persistence services, like S3 or DynamoDB, to store state.
Upvotes: 1