aws lambda: invoke function via other lambda function - amazon-web-services

I have an AWS Lambda function, that need's ~ 30 seconds.
When I connect it to the API Gateway, it's sending a 504 because of the 5 second timeout. So my easyCron Job is failing and will not try it again (I only have a free plan)
So I need an API, that sends a correct 200 status.
My Idea:
Invoke the long term lambda via a short term lambda.
The policy is allowing the invocation.
Here is the code
var AWS = require('aws-sdk'),
params = {
FunctionName: 'cctv',
InvocationType: 'RequestResponse',
LogType: 'Tail'
},
lambda;
AWS.config.update({region: 'us-east-1'});
lambda = new AWS.Lambda();
exports.handler = function (event, context) {
'use strict';
lambda.invoke(params, function (err, data) {
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
}
});
context.succeed('hey cron job, I think my lambda function is not called');
};
But I think, context.succeed() aborts the execution of lambda.invoke()
Do you have any idea how to solve this?

This is incorrect
InvocationType: 'RequestResponse'
You should use
InvocationType: 'Event'
From http://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_RequestSyntax
By default, the Invoke API assumes "RequestResponse" invocation type. You can optionally request asynchronous execution by specifying "Event" as the InvocationType.

Rather than directly calling your 30+ second Lambda function, you could trigger it from an SNS or S3 PutObject event. This would be asynchronous to your API Gateway route, so it can return very quickly. Of course, you would not have the outcome of the Lamdba job at that time.

Related

AWS lambda destination not triggering

My current Lambda Setup
My child lambda in destination not triggering by Main Lambda. It only triggers when i use --invocation-type Event in aws cli. It is not triggering when testing or in live mode. Main lambda works fine in both ways, but it just not triggers destination lambda without cli command.
Full aws cli that works.(But i won't use aws-cli to trigger. It should be triggered by Cloudfront)
aws lambda invoke --function-name main-lambda --cli-binary-format raw-in-base64-out --payload '{"test": 15}' --invocation-type Event response.json
Main Lambda
const https = require("https");
exports.handler = async (event, context, callback) => {
await post("https://example.com/notify", {
type: "viewer-response",
event,
context,});
let response = "";
try {
response = event.Records[0].cf.response;
} catch (e) {
response = event; //For debug purposes
}
// Added this, but not working either.
//response.headers['x-amz-invocation-type'] = [{key: 'X-Amz-Invocation-Type', value: 'Event'}];
return response;
};
Child Lambda
const https = require('https');
exports.handler = async (event,context,callback) => {
console.log("Triggered Child Lambda");
await post("https://example.com/notify", {
type: "onSuccess-response",
event,
context, });
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response; // I don't need this. This comes from base
}
I understand that Main Lambda should be invoked with Event type because it needs to be async in order to call destination lambda but i can't be able to find a way to do it. I tried adding Environment variables to lambda function but it didn't worked either.
That is the expected behaviour. CloudFront invokes Lambdas using the synchronous invocation mode. The service waits for a response from the Lambda. Destinations are ignored.

SQS does not trigger Lambda within 5 minutes in sequential

I'm new to AWS and working on SQS to trigger a lambda function.
The order of the function is,
Lambda A and pass queue to SQS, then SQS trigger Lambda B.
When I run Lambda A, I see Lambda B is triggered as I expected. However, when I run Lambda A within 5 minutes after the last run of Lambda A, Lambda B is not triggered. I'm wondering if there is a default time set of "5 minutes" to use SQS triggering Lambda function. If so, how can I change to "0 minute"?
Does anybody have the similar issue before? Thanks,
// Lambda A
// sends multiple messages to an Amazon SQS queue
module.exports.handler = async (event, context, callback) => {
try {
// sendQueue function is imported in the head of the file
await sendQueue({ queueMessage }, QUEUE_URL)
} catch (e) {
console.error(e)
}
return {
statusCode: 200,
body: JSON.stringify(
{
message: 'Lambda A is done',
input: event,
},
null,
2
),
}
}
// Lambda B
// After SQS receives queues from Lambda A, SQS triggers to invoke Lambda B
module.exports.handler = async (event, context, callback) => {
// here calling Athena query with "await"
return `Successfully processed a message.`;
}
In Lambda B, it gets a message content everytime the function receives a message from SQS like below.
[
{
messageId: 'b4146e42-a542-4e0e-bff9-ba7f96xxxxxx',
receiptHandle: 'xxxxxxxxxxxxxxx',
body: '{"queueMessage": "queueMessage sample text"}',
attributes: {
ApproximateReceiveCount: '1',
SentTimestamp: '1643094105466',
SequenceNumber: '18867376164708847616',
MessageGroupId: '123',
SenderId: 'xxxxxxxx:lambda-function-name',
MessageDeduplicationId: 'xxxxxx',
ApproximateFirstReceiveTimestamp: '1643094105466'
},
messageAttributes: { ReceiveMessageWaitTimeSeconds: [Object] },
md5OfMessageAttributes: 'aaaaaaaa',
md5OfBody: 'bbbbbbb',
eventSource: 'aws:sqs',
eventSourceARN: 'arn:aws:xxx.fifo',
awsRegion: 'ap-northeast-1'
}
]
After going over AWS documentation, I found the line below
If a message with a particular message deduplication ID is sent
successfully, any messages sent with the same message deduplication ID
are accepted successfully but aren't delivered during the 5-minute
deduplication interval.
Basically, using FIFO queue of SQS, the messages sent during 5 minutes won't be delivered to avoid sending duplicate messages.
Just ensure that you have not set the below setting in SQS. This setting could delay your Lambda function to running after x time.

AWS SDK function is not being called when run used on a lambda function deployed by Amplify

I'm trying to add a user to a group in my Amplify project programatically. I created a lambda function as shown below and deployed it using amplify functions. I setup the permissions to the functions's role following this article: https://www.linkedin.com/pulse/aws-amplify-adding-user-group-programmatically-guillermo-misa-iii. The function get's executed. No errors. It doesn't even run the console log which means the callback is not being called. The user is not being added to the group either. There's no error logs in the lambda function logs. Any idea what's happening?
const AWS = require('aws-sdk');
exports.handler = async (event, context, callback) => {
const cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider();
cognitoIdentityServiceProvider.adminAddUserToGroup({
GroupName: 'abcd', //your confirmed user gets added to this group
UserPoolId: event.arguments.userPoolId,
Username: event.arguments.userName
}, function(err, data) {
console.log('Ran the function')
if (err) {
callback(err) // uh oh, an error
}
callback(null, event); // yay! success
})
// return response;
};
In the guide I followed, they have used a normal function as the lambda handler:
exports.handler = (event, context, callback) => {})
But I have used an async function:
exports.handler = async (event, context, callback) => {})
It seems in an async function, lambda does not wait till the callback is called. It expects us to use the async await syntax in our code. So, I have to convert the function like this:
try {
await cognitoIdentityServiceProvider.adminAddUserToGroup({
GroupName: 'abcd', //your confirmed user gets added to this group
UserPoolId: event.arguments.userPoolId,
Username: event.arguments.userName
}).promise()
callback(null, event); // yay! success
} catch (error) {
console.log(error)
}
Now everything works! Notice that we can get a promise out of aws-sdk functions if we call .promise().

Amazon Lambda & API Gateway - 'event.source_ip' returns 'null'

I'm trying to grab the IP of users.
I followed guides on how to do this, and found answers that use event.source_ip in the lambda function, which connects to the API Gateway.
The result returns 'null' in my Lex & Facebook bots, and returns 'test-invoke-source-ip' in the API Gateway Test.
Lambda:
exports.handler = (event, context, callback) => {
callback(null, event.source_ip);
};
API Gateway: Integration Request
Use lambda proxy integration, then you can handle the event and context from the lamda function yourself. You can read more here. https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
You will need to return expected output for it to work.
Example using node (untested):
exports.handler = (event, context, callback) => {
var res = {
"statusCode": 200,
"body": context.identity.sourceIp,
"isBase64Encoded": false,
}
callback(null, res);
}

NodeJS script works locally but not in the handler of lambda

I have a NodeJS Lambda function that reads from a Kinesis stream, does some processing and writes it to another Kinesis stream. The writing part is causing an error on lambda. We use the aws-sdk npm module to write the data. When we call putRecord no callback is fired and lambda times out.
This writing code works well when run locally as a node app on a laptop.
Local config:
- The credentials of a programmatic user are with Kinesis Full Access policy are stored in the credentials file and the putRecord runs successfully returning the shardId, sequence number, etc.
Lambda function:
- The code for putRecord does not return and it hangs. No errors are thrown either. Lambda has a role with the Kinesis Full Access policy.
Code:
var AWS = require('aws-sdk');
var kinesis = new AWS.Kinesis({
region: 'us-east-1',
});
var randomNumber = Math.floor(Math.random() * 100000);
var data = 'data-' + randomNumber;
var partitionKey = 'pk-' + randomNumber;
var recordParams = {
Data: data,
PartitionKey: partitionKey,
StreamName: streamName
};
kinesis.putRecord(recordParams, function(err, data) {
console.log(data);
if (err) {
console.error(err);
}
});
Any idea what could be causing the issue. VPC or security group related maybe?
Thoughts and suggestions appereciated.
Thanks.
If you have uploaded the exact Node.js script code above to Lambda, it will definitely not work.
Lamda requires you to export a handler function that it will call.
So, your script should be written like this if you want it to be a Lambda function...
'use strict';
var AWS = require('aws-sdk');
var kinesis = new AWS.Kinesis({
region: 'us-east-1',
});
exports.handler = function (event, context, callback) {
var randomNumber = Math.floor(Math.random() * 100000);
var data = 'data-' + randomNumber;
var partitionKey = 'pk-' + randomNumber;
var recordParams = {
Data: data,
PartitionKey: partitionKey,
StreamName: streamName,
};
kinesis.putRecord(recordParams, function (err, data) {
callback(null, data);
if (err) {
callback(err);
}
});
};
Take note that instead of using console.log or console.error, you should call callback instead.
When you add a function to a VPC it only has access to resources inside that VPC. Any attempt to access resources outside the VPC will hang and eventually timeout. Since Kinesis doesn't exist inside your VPC, you can't access it.
The fix is to either run the Lambda function outside the VPC, or add a NAT Gateway to your VPC.