How can I call another Lambda function from current Lambda function? - node.js

I have 2 Lambda function. First fetch data from database and put it in DynamoDB. And Second fetch data from the DynamoDB. I want to execute both lambda function sequentially (i.e.first then second). How could I invoke 2nd Lambda function inside 1st Lambda function? How to pass data to that Lambda function? And how to get response from the 2nd Lambda function? Does anyone know possible way? Please help.... Thank u....

For nodejs you can use lambda.invoke function to execute another lambda
var aws = require("aws-sdk");
var lambda = new aws.Lambda({
region: "us-west-1",
});
var params = {
FunctionName: "MyFunction",
InvocationType: "RequestResponse",
LogType: "Tail",
Payload: "<Stringified oject to pass parameters as event>",
};
lambda.invoke(params, function (err, data) {
if (err) console.log(err, err.stack);
// an error occurred
else console.log(data); // successful response
});
for info visit this link:
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property

Related

How do I call another AWS function within the same handler.js file? And attach query string parameters?

I am using AWS Lambda and I have 2 functions within my handler.js file. I want to call the one function (getClient) within the other function. The problem I am having is that the first function (getClient) needs query string parameters and I don't know how to attach that when calling the function.
I have tried changing the event object that is sent to the function and adding the query string parameter as a json but that doesn't work.
let json = JSON.parse(event.body);
event = {
emailAddress: json.clientEmailAddress
}
var client = this.getClient(event);
console.log(client)
I get the error that queryStringParameter is undefined.
errorType": "TypeError",
"errorMessage": "Cannot read property 'queryStringParameters' of undefined",
To invoke an AWS Lambda function from another function, I would suggest to use the AWS SDK and use the invoke API call.
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property
Invoke is taking an PayLoad parameter that can contain any object.
For example :
try {
const lambdaParams = {
FunctionName: 'my-lambda',
// RequestResponse is important here. Without it we won't get the result Payload
InvocationType: 'RequestResponse',
LogType: 'Tail', // other option is 'None'
Payload: queryStringParameters
};
const lambda = new AWS.Lambda({region: 'eu-west-1', apiVersion: '2015-03-31'});
const const lambdaResult = await lambda.invoke(JSON.stringify(lambdaParams.Payload)).promise();
logger.debug(`Lambda returned : ${lambdaResult.Payload}`);
const resultObject = JSON.parse(lambdaResult.Payload)
} catch (e) {
console.error(e);
}

AWS Lambda finish before sending message to SQS

I'm running a "Node.JS" lambda on AWS that sends a message to SQS.
For some reason the SQS callback function get execute only once every couple of calls. It's looks like that the thread that running the lambda finish the run (because it's not a synchronous call to SQS and also can't return a Future) and therefore the lambda doesn't "stay alive" for the callback to get executed.
How can I solve this issue and have the lambda wait for the SQS callback to get execute?
Here is my lambda code:
exports.handler = async (event, context) => {
// Set the region
AWS.config.update({region: 'us-east-1'});
// Create an SQS service object
var sqs = new AWS.SQS({apiVersion: '2012-11-05'});
const SQS_QUEUE_URL = process.env.SQS_QUEUE_URL;
var params = {
MessageGroupId: "cv",
MessageDeduplicationId: key,
MessageBody: "My Message",
QueueUrl: SQS_QUEUE_URL
};
console.log(`Sending notification via SQS: ${SQS_QUEUE_URL}.`);
sqs.sendMessage(params, function(err, data) { //<-- This function get called about one time every 4 lambda calls
if (err) {
console.log("Error", err);
context.done('error', "ERROR Put SQS");
} else {
console.log("Success", data.MessageId);
context.done(null,'');
}
});
};
You should either stick to callback based approach, or to promise based one. I recommend you to use the latter:
exports.handler = async (event, context) => {
// Set the region
AWS.config.update({region: 'us-east-1'});
// Create an SQS service object
var sqs = new AWS.SQS({apiVersion: '2012-11-05'});
const SQS_QUEUE_URL = process.env.SQS_QUEUE_URL;
var params = {
MessageGroupId: "cv",
MessageDeduplicationId: key,
MessageBody: "My Message",
QueueUrl: SQS_QUEUE_URL
};
console.log(`Sending notification via SQS: ${SQS_QUEUE_URL}.`);
try {
await sqs.sendMessage(params).promise(); // since your handler returns a promise, lambda will only resolve after sqs responded with either failure or success
} catch (err) {
// do something here
}
};
P.S. Instantiating aws classes in the handler is not a good idea in lambda environment, since it increases the cold start time. It's better to move new AWS.SQS(...) action out of handler and AWS.config.update() too, since these actions will be executed on each call of the handler, but you really need them to be executed only once.

AWS Lambda node-soap function (serverless framework)

I am testing a call to a SOAP service using node-soap library.
This works fine as a standalone node.js app and the SOAP service responds, however when I package the same code up as a serverless AWS lambda function (using serverless framework, but also executed directly in AWS lambda), it doesn’t appear to create the soap client.
Any thoughts on why this might be happening?
export async function main(event, context) {
var soap = require('soap');
var url = 'https://service.blah.co.uk/Service/Function.asmx?wsdl';
var soapOptions = {
forceSoap12Headers: true
};
var soapHeader = {
'SOAPAction': 'http://www.blah.co.uk/Services/GetToken'
};
var params = {
xmlMessage: message
};
console.log(JSON.stringify(params));
soap.createClient(url, soapOptions, function (err, client) {
//the serverless AWS lambda function never reaches this point (deployed and invoked locally)
console.log("In create client")
if (err) console.log(err);
client.addSoapHeader(soapHeader);
client.GetToken(params, function (err, data) {
console.log(data);
});
});
}
I have created a very minimal working example using async/await. Rather using the old style callback approach, just invoke soap.createClientAsync(url).
Here's the code:
'use strict';
const soap = require('soap');
module.exports.hello = async (event, context) => {
const url = 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl';
const client = await soap.createClientAsync(url)
console.log(client)
return {
statusCode: 200,
message: 'It works!'
}
}
And here are the logs (partially):
EDIT: Function's output (via AWS's Lambda Console)
EDIT 2 - The REAL problem
Check the link above around async/await. The async keyword will execute asynchronously and will return a Promise. Since it's an asynchronous function, your Lambda is being terminated before it could actually execute your callback.
Using async/await will make your code simpler and will have you stop beating your brains out for such a small thing like this.

Return data from async AWS Lambda

How do I get the data back from a lambda invoked with as an event to the calling function?
Essentially the lambda function I have is:
exports.handler = function(event, context, callback) {
var data = {};
data.foo ='hello';
callback(null, data)
}
and the invoking function looks like this:
var AWS = require('aws-sdk');
var lambda = new AWS.Lambda();
var params = {
FunctionName: 'SomeFunction',
InvocationType: 'Event'
};
lambda.invoke(params, function (err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
} else {
console.log(JSON.stringify(data, null, 2));
}
});
However the only thing I get back from the function is
{
"StatusCode": 202,
"Payload": ""
}
I thought the point of the callback parameter was to allow the invoking function to get the data when the function has finished. Am I using it wrong or is what I am asking not possible with Lambdas?
When you invoke the Lambda function you need to set the InvocationType to 'RequestResponse' instead of 'Event'.
When using the Event type your callback is invoked when the payload has been received by AWS's servers. When using the RequestResponse type your callback is invoked only after the Lambda function has completed and you will receive the data it provided to its callback. It is not possible to do what you want with the Event type.
As #MatthewPope commented in this answer, if you do need the results from an asynchronous Lambda execution, you should consider having the Lambda function write its results to S3 (or something to that effect) at a known location where clients of the Lambda function can periodically check for the existence of the result.

AWS Lambda get context message

I am using the test function from AWS console:
console.log('Loading event');
exports.handler = function(event, context) {
console.log('value1 = ' + event.key1);
console.log('value2 = ' + event.key2);
console.log('value3 = ' + event.key3);
context.done(null, 'Hello World'); // SUCCESS with message
};
And calling it in nodejs as follows:
var params = {
FunctionName: 'MY_FUNCTION_NAME', /* required */
InvokeArgs: JSON.stringify({
"key1": "value1",
"key2": "value2",
"key3": "value3"
})
};
lambda.invokeAsync(params, function(err, data) {
if (err) {
// an error occurred
console.log(err, err.stack);
return cb(err);
}
// successful response
console.log(data);
});
and everything works fine:
//Console Output
{ Status: 202 }
But I was expecting to receive the message from context.done(null, 'Message') as well...
Any idea how to get the message?
As Eric mentioned, currently Lambda doesn't offer a REST endpoint to run the function and return its result, but may in the future.
Right now, your best bet would be to use a library like lambdaws, which wraps the function deployment and execution for you and handles returning results via an SQS queue. If you'd like more control by rolling your own solution, the process is straightforward:
Create an SQS queue
Have your Lambda function write its result to this queue
In your client, poll the queue for a result
You are calling invokeAsync, so your Lambda function is run asynchronously. This mean you get the success means back at the point your function is successfully started, and not after it completes.
As of this writing, AWS Lambda does not yet offer a way to invoke a function synchronously, returning information from the function directly back to the caller. However, this appears to be a common request and Amazon has publicly stated they are considering the feature.

Resources