AWS NodeJS lambda call within a lambda function - node.js

I've trying to call lambda function from another lambda function and get result to execute rest of the lambda.
Basic flow of function is below
X - main lambda function
- process A (independent)
- process C (need input from process B)
- process D
- return final dataset
Y - Child lambda function
- process B ( need input from process A and respond back to X )
This is my code so far
var AWS = require('aws-sdk');
AWS.config.region = 'us-east-1';
var lambda = new AWS.Lambda();
const GetUserCheckoutData: Handler = async (userRequest: EmptyProjectRequest, context: Context, callback: Callback) => {
const dboperation = new UserController();
const usercheckoutdata = new CheckOutInfo();
const addresscontroller = new AddressController();
const ordercontroller = new OrderController();
const paypalcreateorder = new PayPalController();
const userid = await dboperation.getUserID(userRequest.invokeemailAddress);
usercheckoutdata.useraddressdetails = await addresscontroller.GetListOfAddressByUserID(userid);
var orderlist = new Array<Order>();
orderlist = [];
orderlist = await ordercontroller.GetCurrentOrder(userid);
console.log("Order Complete");
var params = {
FunctionName: 'api-ENGG-SellItem', // the lambda function we are going to invoke
InvocationType: 'RequestResponse',
LogType: 'Tail',
Payload: '{ "orderlist" : xxxxxxx }'
};
lambda.invoke(params, (err:any, res:any) => {
if (err) {
callback(err);
}
console.log(JSON.stringify(res));
callback(null, res.Payload);
});
usercheckoutdata.orderID = await paypalcreateorder.CreateOrder(userid , orderlist);
usercheckoutdata.orderPreview = await ordercontroller.OrderPreview(userid);
//callback(null,usercheckoutdata);
};
export { GetUserCheckoutData }
I tried a few different ways but flow is not working properly. cross lambda function is executing. but cannot get the response on time.
My child lambda function demo code
import { Handler, Context } from "aws-lambda";
const SellItem: Handler = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
console.log("Other Lambda Function");
setTimeout(() => {
callback(null, "My name is Jonathan");
}, 1000 * 10); // 10 seconds delay
}
export {SellItem}
I think since I don't have much NodeJS knowledge this is happening. don't know how to put call back in right way I guess. Any help will be appreciated

You should make your call to the second lambda a promise, so you can await it.
const res = await lambda.invoke(params).promise();
// do things with the response

Related

Return the value gotten from lambda.invoke (NodeJS / Typescript)

I'm basically trying to invoke a lambda function using the lambda.invoke function i found in this question (in NodeJs), but i want to return the value so i can use it outside the function and make changes to it, rather than just console.log the output. This is the code i'm trying and isn't working:
var AWS = require('aws-sdk');
AWS.config.region = 'my region';
var lambda = new AWS.Lambda();
var params = {
FunctionName: 'arn:aws:lambda:us-east-1:XXXXXXXXXXXX:function:random-function',
// the lambda function we are going to invoke
InvocationType: 'RequestResponse',
LogType: 'Tail',
Payload: JSON.stringify({"text": 'test 123'})
};
var output_lambda = 'output of lambda'
lambda.invoke(params, function(err, data) {
output_lambda = String(data.Payload)
return output_lambda
});
console.log(output_lambda)
// returns 'output of lambda' instead of the actual output
I've tried some other methods and none of them worked as well, i am very new to NodeJs and AWS, so i'm sorry if this sounds like a dumb question, thank you in advance.
For some reason i didn't see this answer to the question: Nodejs - Invoke an AWS.Lambda function from within another lambda function, that answered my question and all i had to do was tweak it a bit. Here is my new code, and thank you to Oscar Fernandez Sierra for this answer.
const g_LambdaFunctionName = 'name'; // <======= PUT THE DESIRED VALUE
const AWS = require('aws-sdk');
AWS.config.region = 'us-east-1';
const lambda = new AWS.Lambda;
//
// Expected use:
//
// // (payload can be an object or a JSON string, for example)
// let var = await invokeLambda(lambdaFunctionName, payload);
//
const invokeLambda = async (lambdaFunctionName, payload) => {
let payloadStr;
if (typeof payload === 'string')
{
payloadStr = payload;
}
else
{
payloadStr = JSON.stringify(payload, null, 2);
}
let params = {
FunctionName : lambdaFunctionName, /* string type, required */
// ClientContext : '', /* 'STRING_VALUE' */
InvocationType : 'RequestResponse', /* string type: 'Event' (async)| 'RequestResponse' (sync) | 'DryRun' (validate parameters y permissions) */
// InvocationType : 'Event',
LogType : 'None', /* string type: 'None' | 'Tail' */
// LogType : 'Tail',
Payload : payloadStr, /* Buffer.from('...') || 'JSON_STRING' */ /* Strings will be Base-64 encoded on your behalf */
// Qualifier : '', /* STRING_VALUE' */
};
//
// TODO/FIXME: add try/catch to protect this code from failures (non-existent lambda, execution errors in lambda)
//
const lambdaResult = await lambda.invoke(params).promise();
// The actual value returned by the lambda it is lambdaResult.Payload
// There are other fields (some of them are optional)
return lambdaResult;
};
var callingFunc = async () => {
//
// in this example We obtain the lambda name from a global variable
//
const lambdaFunctionName = 'ARN to my Lambda';
// const payload = '{"param1" : "value1"}';
const payload = JSON.stringify({"text": text});;
//
// invokeLambda has to be called from a async function
// (to be able to use await)
//
const result = await invokeLambda(lambdaFunctionName, payload);
return String((result.Payload))
};
callingFunc();

AWS lambda sending sns message to phone number

I have a lambda function running node.js The function makes database calls and sends a text message via sns. It has the following structure
the functions -> index.js file looks like this
async function sendTextMessage(message, phoneNumber) {
try {
console.log("hitSendFunction");
const sns = new AWS.SNS();
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: phoneNumber
};
//remember phone number must have +1 before it.
return await sns.publish(params).promise();
} catch (error) {
console.log(error);
}
}
module.exports = {
sendTextMessage
};
that function is than called in the main index.js file:
const database = require("./db");
const { sendTextMessage } = require("./functions");
const AWS = require("aws-sdk");
AWS.config.region = "us-east-1";
exports.handler = async function (event, context) {
try {
console.log("hit");
const result = await database.query("call getTicker()");
const data = result[0][0];
const currentProjectEndDate = new Date(
data.currentProjectEndDate
).getTime();
const now = new Date().getTime();
console.log("data.currentProjectEndDate", data.currentProjectEndDate);
const runningHot =
data.jobsInQueue > 0 && currentProjectEndDate <= now && data.textSent < 1;
if (runningHot) {
const numbers = ["+1435994****"];
for (let i = 0; i < numbers.length; i++) {
let number = numbers[i];
console.log("number", number);
let messageResult = await sendTextMessage(
"The CE Bot is running hot from lambda",
number
);
console.log("messageResult", messageResult);
}
await database.query("call insertIntoTextSent()");
console.log("yes");
}
} catch (error) {
console.log("this was the error", error);
}
The database calls work correctly but the textMessage function just hangs and times out. The lambda function has the following permissions attached to it:
Finally even though I do not think it is needed as the db code is working here is what the db -> index.js file looks like:
const mysql = require("mysql");
const util = require("util");
const awsConfig = {
host: process.env.RDS_HOST,
user: process.env.RDS_USER,
password: process.env.RDS_PASSWORD,
database: process.env.RDS_DATABASE
};
const connection = mysql.createConnection(awsConfig);
connection.query = util.promisify(connection.query.bind(connection));
connection.end = util.promisify(connection.end.bind(connection));
module.exports = connection;
I am not quite sure where I am going wrong here. Can someone point me in the right direction?
You can just send it via sms in sns just type in the phone number

how to save data in aws neptune db using node js?

Is there a way to save the data in amazon aws neptune db using node js?
I am running this code on a lambda.
I made the connection to neptune db using the below code.
const gremlin = require('gremlin');
const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
const Graph = gremlin.structure.Graph;
dc = new DriverRemoteConnection('endpoint',{});
const graph = new Graph();
const g = graph.traversal().withRemote(dc);
Here's a JavaScript Lambda function that writes data to Neptune (and wraps the write in a retry block in case of concurrent modifications). The function gets the Neptune endpoint and port from environment variables. The write query is in the query() method. It's a simple upsert example that tries to create a vertex using a randomly generated ID. If a vertex with that ID already exists, the query returns that vertex rather than creating a new one.
This example creates a single connection that persists for the lifetime of the Lambda container (rather than per invocation). There's some error checking in the retry code that recreates the connection in the case of an untoward network issue.
const gremlin = require('gremlin');
const async = require('async');
const traversal = gremlin.process.AnonymousTraversalSource.traversal;
const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
let conn = createRemoteConnection();
let g = createGraphTraversalSource(conn);
const t = gremlin.process.t;
const __ = gremlin.process.statics;
async function query(id) {
return g.V(id)
.fold()
.coalesce(
__.unfold(),
__.addV('User').property(t.id, id)
)
.id().next();
}
exports.handler = async (event, context) => {
const id = Math.floor(Math.random() * 10000).toString();
return async.retry(
{
times: 5,
interval: 1000,
errorFilter: function (err) {
// Add filters here to determine whether error can be retried
console.warn('Determining whether retriable error: ' + err.message);
// Check for connection issues
if (err.message.startsWith('WebSocket is not open')){
console.warn('Reopening connection');
conn.close();
conn = createRemoteConnection();
g = createGraphTraversalSource(conn);
return true;
}
// Check for ConcurrentModificationException
if (err.message.includes('ConcurrentModificationException')){
console.warn('Retrying query because of ConcurrentModificationException');
return true;
}
return false;
}
},
async function (cb) {
let result = await query(id);
return result['value'];
});
};
function createRemoteConnection() {
return new DriverRemoteConnection(
connectionString(),
{
mimeType: 'application/vnd.gremlin-v2.0+json',
pingEnabled: false
});
}
function createGraphTraversalSource(conn) {
return traversal().withRemote(conn);
}
function connectionString() {
return 'wss://' +
process.env['neptuneEndpoint'] +
':' +
process.env['neptunePort'] +
'/gremlin';
}
Simple demo based off the TinkerPop documentation
const handler = async (event) => {
// add person vertex with a property name and value stephen.
await g.addV('person').property('name','stephen').next();
// fetch all vertex' and get the name properties.
const result = await g.V().values('name').toList();
console.log(result);
return {
statusCode: 201,
body: JSON.stringify({message:"Testing Gremlin!", data:result}),
};
}

Lambda#Edge when triggered Dynamodb giving 503 Error

I am trying to invoke Lambda through cloudfront viewer request . Here is my Lambda code
'use strict';
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
/* Get request */
const request = event.Records[0].cf.request;
const requestbody = Buffer.from(request.body.data, 'base64').toString();
const data = JSON.parse(requestbody);
const Id = data.Name;
console.log(Id);
/* Generate body for response */
const body =
'<html>\n'
+ '<head><title>Hello From Lambda#Edge</title></head>\n'
+ '<body>\n'
+ '<h1>You clicked more than 10 Times </h1>\n'
+ '</body>\n'
+ '</html>';
var params = {
TableName: "Test",
ProjectionExpression: "#V,#N",
KeyConditionExpression: "#N = :v1",
ExpressionAttributeNames: {
"#N" : "Name",
"#V" : "Value"
},
ExpressionAttributeValues: {
":v1": Id
}
};
var querydb = docClient.query(params).promise();
querydb.then(function(data) {
console.log(data.Items[0].Value);
if(data.Items[0].Value >= 11){
const response = {
status: '200',
body: body,
};
callback(null, response);
}else {
callback(null,request);
}
}).catch(function(err) {
console.log(err);
});
};
When i triggered the same lambda through console it is giving correct response. But when i deployed through Cloudfront it is giving 503 Error. But i had tried the same code withcode Dynamodb Client it worked perfectly fine. Here is the working one
'use strict';
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
/* Get request */
const request = event.Records[0].cf.request;
const requestbody = Buffer.from(request.body.data, 'base64').toString();
const data = JSON.parse(requestbody);
/* Generate body for response */
const body =
'<html>\n'
+ '<head><title>Hello From Lambda#Edge</title></head>\n'
+ '<body>\n'
+ '<h1>You clicked more than 10 Times </h1>\n'
+ '</body>\n'
+ '</html>';
if(data.Value >= 10){
const response = {
status: '200',
body: body,
};
callback(null, response);
}
else {
callback(null, request);
}
};
I had given full dynamodb permissions to the lambda#edge.
Any help is appreciated
Thanks
Where have you specified region for DyanamoDB?
It is possible that Lambda#Edge is executing in a region where your DDB table is missing.
Have a look at AWS doc on region's order of precedence. You can also look at this L#E workshop code and documentation for more details on calling DDB.
On a side note: A viewer facing Lambda function, making a call to a cross region dynamodb table will have negative effects on your latency. Not sure about your use case but see if it is possible to move this call to an origin facing event or make async call to ddb.

AWS Lambda cannot publish to IoT topic properly

I have written Lambda function using JavaScript, which responses to my voice and turns on the LED on my Raspberry.
But I have a problem with publishing its state to my thing topic. While Alexa responses correct ("Turning on" if Im asking to turn it on and "Turning off" if asking to off), my topic doesn't always get the state changes. Some times it gets data and sometime it doesn't and after few more invocations it gets data in bulk, and I cant even get the logic of creating a sequence of data in that bulk.
var AWS = require('aws-sdk');
var config = {};
config.IOT_BROKER_ENDPOINT = "xxxxxx.iot.us-east-1.amazonaws.com";
config.IOT_BROKER_REGION = "us-east-1";
config.IOT_THING_NAME = "raspberry";
var iotData = new AWS.IotData({endpoint: config.IOT_BROKER_ENDPOINT});
var topic = 'LED';
exports.handler = function (event, context) {
...
...
function updatePowerState (intent, session, callback) {
var speechOutput = '';
var newValue = '';
var repromptText = '';
const cardTitle = 'Power';
var sessionAttributes = {};
const shouldEndSession = true;
var value = intent.slots.PowerState.value;
if(value == 'on' || value == 'off') {
newValue = value.toUpperCase();
speechOutput = 'Turning your lamp ' + value;
updateShadow(newValue);
} else {
speechOutput = 'I didnt understand you. Please, repeat your request.';
}
callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
}
function updateShadow(newValue) {
let payload = {
state: {
desired: {
power_state: newValue
}
}
};
var JSON_payload = JSON.stringify(payload);
var updates = {
topic: topic,
payload: JSON_payload,
qos: 0
};
iotData.publish(updates, (err, data) => {
if(err) {
console.log(err);
}
else {
console.log('Success!');
}
});
}
Do you have any ideas about its causes? Thank you!
Async methods like iotData.publish cause problems into AWS Lambda, because you request a execution and the lambda function ends soon without waiting for the response and processing the request.
Another problem could be your permissions.
var AWS = require('aws-sdk');
var iotdata = new AWS.IotData({endpoint: 'iotCoreEndpoint.iot.us-east-1.amazonaws.com'});
exports.handler = async (event) => {
var params = {
topic: 'topic/topicName',
payload: JSON.stringify(event.body),
qos: 0
};
await iotdata.publish(params).promise()
};
Just make sure to add the required permissions or you can attach the following policy to your lambda role: AWSIoTWirelessFullPublishAccess

Resources