AWS Node.js Lambda Invoking Lambda Failing - node.js

The AWS Lambda.invoke command seems to do nothing for me. It neither throws an error nor returns. I've read tonnes of posts and I think have all the ARN right. But since the 'invoke' never happens, I assume this is an ARN issue? Any ideas?
Code:
var AWS = require('aws-sdk');
AWS.config.region = 'us-east-1';
var lambda = new AWS.Lambda();
exports.handler = async (event) => {
var params = {
FunctionName: 'myfunction',
InvocationType: 'Event',
LogType: 'Tail',
Payload: '{"sample_param": "payload_string"}'
};
lambda.invoke(params, function(err,data){
if (err) {
console.log("Error");
} else {
console.log("Returned: " + data.Payload);
}
});
};
This returns:
ARN / Policies:
Solution, I'm an idiot and didn't use a promise:
exports.handler = async (event) => {
var params = {
FunctionName: 'my_fuction',
InvocationType: 'RequestResponse',
Payload: '{"my_param": "my_value"}'
};
return lambda.invoke(params).promise();
};

Related

Inconsistent DynamoDB writtings

We have the following code used as lambda Function in Serverless Framework triggered every 2min with cron. The issue we are facing is that the writing in DynamoDB is inconsistent , we want to have 3 writings but instead we receive 1 or 2 writings every 2 minutes.
DynamoDB has a HASH key the HOUR and SORT KEY the DATE and Billing mode: PROVISIONED. Has someone faced the same behavior from DynamoDB or the same issue to share how he sovled it. Thanks
"use strict";
const AWS = require("aws-sdk");
const axios = require("axios");
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const lambda = new AWS.Lambda({
region: "us-east-1",
});
module.exports.getWeather = async (event, context, callback) => {
const openWeatherMapAPIURL = `http://api.openweathermap.org/data/2.5/weather?id=${event}&appid=XXXXXXXXXXXXXXXXXXXXXXX&units=metric`;
const currentWeather = await axios
.get(openWeatherMapAPIURL)
.then((records) => {
console.log(records);
const d = new Date(records.headers.date);
let hour = d.getHours();
const params = {
TableName: process.env.DYNAMODB_TABLE_NAME,
Item: {
hour: hour,
date: records.headers.date,
city: records.data.name,
temp: records.data.main.temp,
feelsLike: records.data.main.feels_like,
description: records.data.weather[0].description,
},
};
setTimeout(function () {
dynamoDb.put(params, (error) => {
// handle potential errors
console.log(`zapis na: ${records.data.name} ${records.headers.date}`);
if (error) {
console.log(error);
console.error(error);
return;
}
});
}, 3000);
})
.catch((error) => {
console.log(error);
return;
});
const response = {
statusCode: 200,
body: JSON.stringify({
message: `Weather from ${event} was requested!`,
}),
};
callback(null, response);
};
module.exports.cron_launcher = (event, context, callback) => {
const requestedID = ["786735", "792578", "785842"];
requestedID.forEach((requestedID) => {
const params = {
FunctionName: process.env.HANDLER_LOCATION + "-getWeather",
InvocationType: "RequestResponse",
Payload: JSON.stringify(requestedID),
};
return lambda.invoke(params, function (error, data) {
if (error) {
console.error(JSON.stringify(error));
return new Error(`Error printing messages: ${JSON.stringify(error)}`);
} else if (data) {
console.log(data);
}
});
});
};
You are not waiting for the dynamodb.put operation to finish. Additionally, you are wrapping the call in a setTimeout. Your lambda function is returning before the network operation can be made. Make sure the put operation succeeds before returning a result from your lambda.
I see no reason for you to use a setTimeout here.
You can call dynamodb.put(...).promise() to get a promise from the dynamodb SDK and await that promise.
2.a Or you can continue using a callback, but wrap the entire section of code in a new promise object, calling the resolve method after the dynamodb.put call finishes.

Not able to fetch data from dynamodb from lambda function

I am trying to fetch data from dynamodb from my lambda.I have written this code
exports.handler = async (event) => {
// TODO implement
var AWS = require('aws-sdk');
AWS.config.update({region: 'ap-south-1'});
var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
var params = {
TableName: 'my_table',
Key: {
'serial_number': {S: '17AB-574C-C1'}
},
};
ddb.getItem(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Item);
console.log(data);
}
});
};
This code works fine when I run locally but I get a null response when I run it on lambda.My lambda has dynamoDbfullAccess policy attached to it. Can anyone tell me what could be the reason?

How to mock an aws lambda function call inside another lambda function with nodejs and mocha

I am writing unit test for a lambda function (exports.handler) with mocha and chai. There is another lambda function call inside the one which I am writing unit test.
I don't want to invoke actual call to the second lambda function. Are there any ways to mock the call to this lambda function?
exports.handler = (event, context, callback) => {
try {
var lambda = new AWS.Lambda();
/*need to mock this lambda call*/
lambda.invoke({
FunctionName: myFunction,
Payload: payload}, function(error, data) {});
}
catch(e){
}
Any helps are really appreciated.
I agree with #AironBrynchke to use consistent approach. Since you already use async/await, let's avoid using callback.
This is how I do to test it.
const AWS = require('aws-sdk');
exports.handler = async (event) =>
{
try
{
const lambda = new AWS.Lambda();
await lambda.invoke(
{
FunctionName: 'whatever', // I changed it for test sample
Payload: 'payload'
}).promise();
}
catch (ex)
{
console.error(ex);
}
};
And for test
const chai = require('chai');
const sinon = require('sinon');
const assert = chai.assert;
const proxyrequire = require('proxyquire');
const invokeStub = sinon.stub().returns({
promise: sinon.stub().resolves()
});
// here we want to mock `Lambda`
const src = proxyrequire('path-to-your-source-file', {
'aws-sdk': {
Lambda: sinon.stub().returns({
invoke: invokeStub
})
}
});
describe('lambda test', function() {
it('runs test', async function() {
await src.handler({});
assert(invokeStub.calledWith({ FunctionName: 'whatever', Payload: 'payload' }));
})
});
First of all, you are mixing two styles. If you are using try && catch block then:
exports.handler = async (event) =>
{
try
{
const lambda = new AWS.Lambda();
await lambda.invoke(
{
FunctionName: myFunction,
Payload: payload
}).promise();
}
catch (ex)
{
console.error(ex);
}
};
How to test your lambda function with mochaJs:
I can provide several references and you can figure out by yourself what is fit to you.
npm lib aws-lambda-mock-context (callbacks)
ref: https://github.com/SamVerschueren/aws-lambda-mock-context
another npm package lambda-tester (callbacks)
ref: https://www.npmjs.com/package/lambda-tester
And take a look at mocking-in-aws-lambda on stackoverflow
ref: Mocking in AWS Lambda

DynamoDB, Lambda function / custom module Timeout

I have the following two JS file. My problem is when i call the Calls.js which calls the Archive.js for archiving logs into DynamoDB the request times out.
I have tried out, many things, read about many things, tried in local/AWS environment without luck. What am i missing?
Link1, Link2, Link3, Link4, Link5,
Archive.js
module.exports.archive = archive;
...
function archive(input, callback){
AWS.config.update({
region: "eu-west-1",
endpoint: "http://localhost:8000"
});
var documentClient = new AWS.DynamoDB.DocumentClient({
httpOptions: {
agent: new https.Agent({
rejectUnauthorized: true,
secureProtocol: "TLSv1_method",
ciphers: "ALL"
})
}
});
...
var paramsPUT = {
TableName: "Logging",
Item: {
HashKey: dbID,
archiveEntry: archiveEntry
}
};
...
documentClient.put(paramsPUT, function(err, data) {
if (err) console.log(err);
if (data) console.log(data);
...
callback(data);
});
}
Calls.js
exports.handler(event, context, callback) => {
const archive = require("./..path..").archive;
...
context.callbackWaitsForEmptyEventLoop = false;
...
archive(input, callback);
...
}
I can not reproduce a timeout condition with your code. Your code is talking to an AWS endpoint at http://localhost:8000, so I assume you have DynamoDB local up and running, don't you ? Failling to have local DynamoDB running would cause the timeout.
That being said, I would strongly suggest to refactor your code to use Promise and the new async/await provided by NodeJS 8 instead of passing the Lambda callback around.
Here is the modified code.
const AWS = require("aws-sdk");
async function archive(input) {
return new Promise( (resolve, reject) => {
AWS.config.update({
region: "eu-west-1",
endpoint: 'http://localhost:8000'
});
//use client specific AWS configuration instead of the global one
const documentClient = new AWS.DynamoDB.DocumentClient();
var paramsPUT = {
TableName: "Logging",
Item: {
HashKey: "123",
archiveEntry: input
}
};
documentClient.put(paramsPUT, function (err, data) {
if (err) {
console.log("ERROR " + err);
reject(err);
}
console.log("Returned from DDB " + JSON.stringify(data, null,2));
resolve(data);
});
});
}
exports.handler = async (event, context, callback) => {
const result = await archive("abc");
callback(result);
}
// stuffs to test locally
callback = function (data) {
console.log("callback called with " + JSON.stringify(data,null,2));
}
event = context = {}
exports.handler(event, context, callback);

Issue with invoking lambda from another lambda

I have 2 Lambda functions that I would like to call directly not through API Gateway. Lambda function A is Calling Lambda B along with queryStringParameters. For some reasons I'm getting this error
{ UnexpectedParameter: Unexpected key 'queryStringParameters' found in params
This is my Lambda A function
var aws = require('aws-sdk');
var lambda = new aws.Lambda({
region: 'eu-central-1'
});
exports.handler = (event, context, callback) => {
var params = {
FunctionName: "function-getStats",
InvocationType: "RequestResponse",
LogType: "Tail",
"queryStringParameters" : { "fn" : "latest_no" }
};
lambda.invoke(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};
Which is calling Lambda B as below
var AWS = require('aws-sdk');
AWS.config.update({region: 'eu-central-1'});
var ddb = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
exports.handler = (event, context, callback) => {
var fn = event["queryStringParameters"]['fn'];
...
..
//If successful return the following response
console.log("Success", items);
callback(null, {
'statusCode': '200',
'body': JSON.stringify(items),
'headers': {
"Access-Control-Allow-Origin": "*"
},
'isBase64Encoded': false
});
Can someone please advise how to fix this?
In case anyone got the same issue. here's the approach I did
var aws = require('aws-sdk');
var lambda = new aws.Lambda({
region: 'eu-central-1'
});
exports.handler = (event, context, callback) => {
event.queryStringParameters= {"fn" : "latest_no" };
var params = {
FunctionName: "function-getStats",
InvocationType: "RequestResponse",
LogType: "Tail",
Payload: JSON.stringify(event, null, 2),
};
lambda.invoke(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};

Resources