I have a Lambda function that imports a node package with common functions. Lambda 1 puts messages into SQS, Lambda 2 does error logging. One of the shared functions invokes Lambda 2, but there's an error on that second invocation.
Lambda 1:
exports.handler = function (event, context) {
var pnmacCommon = require('./pnmacCommon.js'); //loading node package
try {
// this part omitted for space
var aws = require('aws-sdk');
var sqs = new aws.SQS({ region : 'us-west-2' });
var params = {
MessageBody: JSON.stringify(event),
QueueUrl: '[url]'
};
sqs.sendMessage(params, function(err,data){
if(err) {
console.log('error:',"FAIL Send Message: " + err);
context.done(err, "ERROR Put SQS"); // ERROR with message
pnmacCommon.SvtLogErrorToElmah(application, "FAIL Send Message: " + err, context);
}else{
console.log('Message Sent:', queueUrl);
console.log('data:',data.MessageId);
context.done(null,''); // SUCCESS
}
}
});
}
catch (error) {
pnmacCommon.SvtLogErrorToElmah(application, 'SVTMessageBus_Client' + error, context);
context.done(error, "ERROR put SQS");
}
pnmacCommon.js:
var SvtLogErrorToElmah = function (application, error, context) {
console.log("SvtLogErrorToElmah=" + JSON.stringify(error, null, 2));
// this part omitted for space
var aws = require('aws-sdk');
var lambda = new aws.Lambda({region: 'us-west-2' });
lambda.invoke({
FunctionName: "SVTExceptionLogger",
Payload: JSON.stringify(message, null, 2)
}, function (error2, data) {
if (error2) {
context.fail(error2);
} else {
context.fail(error);
});
context.done(null, message);
}
module.exports.SvtLogErrorToElmah = SvtLogErrorToElmah;
Looking in Cloudwatch, I can see that the SvtLogErrorToElmah function gets called, but it fails when it tries to invoke the second Lambda. The error message is TypeError: lambda.invoke is not a function.
Any ideas? Thank you in advance.
It turns out this was an issue with variable scoping. In the shared function, we reuse the variable name aws. Once I changed this to a different name, the problem went away.
I just got the same error that you had, and for me the update of the aws-sdk version resolved the issue.
UPDATED the package.json [aws-sdk version]
old (with 'TypeError: lambda.invoke is not a function')
"dependencies": {
"aws-sdk": "^2.1.17"
}
to (fixed the error)
"dependencies": {
"aws-sdk": "^2.18.0"
}
Related
I am playing the aws mobilehub with react-native and I was hoping that it can speed up the backend hosting for me.
However, I cannot get its backend API working. After a long run with their docs, I pin down the problem between its lambda function and dynamodb service.
Any thoughts are greatly appreciated!
Problem#1
As the titled says: my aws lambda functions can request its dynamodb but has no response.
What went wrong here?
Or how can I get debug info from AWS dynamodb? (I gg and enabled Cloudtrial but it doesn't seem to have operation logs of the dynamodb too.)
Lambda side
Here I have the simplest node.js 6.10 codes:
const AWS = require('aws-sdk');
AWS.config.update({region: 'us-east-2'});
const dynamodb = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, context, callback) {
var responseCode = 200;
var requestBody, httpMethod, res;
console.log("request: " + JSON.stringify(event));
// Request Body
requestBody = event.body;
/*testing dynamodb with put*/
console.log("PUT begins");
let putItemParams2 = {
TableName: "xxxx-mobilehub-xxxx-Test",//tableName
Item: {businessId:'putItemParams2r3',test:'yooo', hmm:'hhhh'}
};
console.log("putItemParams2: ",putItemParams2);
dynamodb.put(putItemParams2, (err, data) => {
console.log("putItemParams2");
if (err) console.log("dynamodb err: ",err, err.stack); // an error occurred
else console.log("dynamodb data: ",data); // successful response
});
console.log("PUT end");
var response = {
statusCode: responseCode
//....
};
...
//comment out context.succeed here to avoid program termination before intended.
//console.log("response: " + JSON.stringify(response))
//context.succeed(response);
};
Logs
When the previouse codes are triggered, from AWS CloudWatch I can see logs:
START RequestId: 3d7c5f7f-1b98-11e8-ad00-93a6d10c8f4e Version: $LATEST
[timestamp] PUT begins
[timestamp] putItemParams2: { TableName: 'xxx-mobilehub-xxxx-Test',
Item: { businessId: 'putItemParams2r3', test: 'yooo', hmm: 'hhhh'}}
[timestamp] put end
END RequestId: 3d7c5f7f-1b98-11e8-ad00-93a6d10c8f4e
So no err, no data, no response. I checked my dynamodb and there is nothing insert.
Extra info
condition#1: this dynamodb table has public access since I want to rule out the auth problem.
condition#2: I ensure that my lambda function has access to these tables. e.g. arn:aws:dynamodb::xxxx:table/xxxx-mobilehub-xxxx- allow everything
condition#3: I build myself a simple node.js to execute the (aws-sdk)and this server works perfectly fine with the same code..
I am able to "get" &"put" items int & out from my dynamodb table.
Problem#2
my react-native code use 'aws-amplify-react-native'. Which the API.put is fine and the lambda function is at least receiving the api call (from problem#1).
However, API.get returns me 403 error, and the lambda function doesn't even has log for this operation..
async function getBusiness(){
const path = "/Test";
const api = "TestCRUD";
let queryGetBusiness = {body: {userId: "hmmm"}};
try {
let apiResponse = await API.get(api, path, queryGetBusiness)//.then((data)=>{console.log(data)});
let apiResponseJson = await JSON.stringify(apiResponse);
console.log("response from saving Business: " + apiResponseJson);
}
catch (e) {console.log(e);}
}
P.S.(AWS could do much better with this mobilehub.. their documentation is lacking details and awsmobile cloud-api invoke has some problems I guess.)
const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-2' });
const dynamodb = new AWS.DynamoDB.DocumentClient();
exports.handler = function (event, context, callback) {
var responseCode = 200;
var requestBody, httpMethod, res;
console.log("request: " + JSON.stringify(event));
// Request Body
requestBody = event.body;
/*testing dynamodb with put*/
console.log("PUT begins");
let putItemParams2 = {
TableName: "xxxx-mobilehub-xxxx-Test",//tableName
Item: { businessId: 'putItemParams2r3', test: 'yooo', hmm: 'hhhh' }
};
console.log("putItemParams2: ", putItemParams2);
dynamodb.put(putItemParams2, (err, data) => {
console.log("putItemParams2");
if (err) console.log("dynamodb err: ", err, err.stack); // an error occurred
else {
console.log("dynamodb data: ", data);
context.succeed(response);
}
// Call these here
console.log("PUT end");
});
//console.log("response: " + JSON.stringify(response))
};
Make sure you call context.succeed inside the callback function. Like above.
You can also just use the third argument to handler function - callback instead of context.succeed like callback(null, response);
I am playing with AWS Lambda along with Twilio. I have a Lambda function that integrates Lex with Twilio. I also have another Lambda function that does the the validations for my LexBot. Both work fine separately. However, I'm trying to put them together so whenever my LexBot integrates with Twilio, it also calls my validations in the same Lambda function.
Any ideas? Thank you.
Here is the Lambda that integrates Lex with Twilio:
var twilio = require('twilio');
var qs = require('qs');
var AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
try {
var twilioSMS = qs.parse(event["body-json"]);
// ************************
// validate and filter bad/empty messages
// ************************
if(!twilioSMS.hasOwnProperty('Body')){
var error = new Error("Cannot process message without a Body.");
callback(error);
}
else {
// Message is valid so now we prepare to pass it along to the Lex API.
AWS.config.region = 'us-east-1';
var lexruntime = new AWS.LexRuntime();
var userNumber = twilioSMS.From.replace('+', '');
var params = {
botAlias: process.env.BOT_ALIAS,
botName: process.env.BOT_NAME,
inputText: twilioSMS.Body,
userId: userNumber,
sessionAttributes: {
}
};
lexruntime.postText(params, function(err, data) {
var twimlResponse = new twilio.TwimlResponse();
if (err) {
console.log(err, err.stack); // an error occurred
twimlResponse.message('Sorry, we ran into a problem at our end.');
callback(err, twimlResponse.toString());
} else {
console.log(data); // got something back from Amazon Lex
twimlResponse.message(data.message);
callback(null, twimlResponse.toString());
}
});
}
} catch(e) {
console.log(e);
callback(e);
}
};
And here is my Lambda with the validations:
exports.handler = (event, context, callback) => {
// TODO implement
var numberType =event.currentIntent.slots.number,
response = "is not valid. Try 'One' or 'Two'." ;
if(numberType === "one" ) {
response = "Call: 111 111 1111 "
}
else if(numberType === "two") {
response = "Call: 222 222 2222"
}
callback(null, {
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled",
"message": {
"contentType": "PlainText",
"content": "Your option: " + event.currentIntent.slots.number + ": " + response
}
}
});
};
Step functions would be your friend. Please have a look at below links,
https://aws.amazon.com/step-functions/
https://cloudacademy.com/blog/aws-step-functions-a-serverless-orchestrator/
I realized didn't need to write a Lambda function to connect Lex with Twilio. All I had to do was go to 'Channels' under my LexBot Console and integrate manually my bot with my Twilio account.
I am getting "Process exited before completing request" while executing lambda function.
When I check the logs in cloud watch it shows the error which says
"Cannot perform operation on a shutdown bucket." or sometimes it says
{ "errorMessage": "Client-Side timeout exceeded for operation. Inspect network conditions or increase the timeout",
"errorType": "CouchbaseError",
"stackTrace": []
}
I am using the following npm packages to communicate with the database server : couchbase, ottoman.
Below is the exports.handler function:
exports.handler = function(event, context, callback) {
function sendResponse(error, data) {
ottoman.bucket.disconnect();
console.log("error : ", error);
console.log("data : ", data);
callback(error, data);
}
console.log("17", event);
if(event.id != undefined) {
user.find({ _id: event.id }, function(error, result) { //this line generates the error
if (error) {
sendResponse(error, null);
}
console.log("22 : ", result);
});
}
});
Below is my database connection file:
var couchbase=require('couchbase');
var ottoman=require('ottoman');
var config = require("./config");
var myCluster = new couchbase.Cluster(config.couchbase.server);
module.exports.bucket = myCluster.openBucket(config.couchbase.bucket,function (error) {
if(error) {
console.log(error);
}
module.exports.bucket.operationTimeout=20000;
module.exports.bucket.n1qlTimeout=100000;
console.log("Successfully opened igt bucket");
ottoman.bucket = module.exports.bucket; });
We also have alternate function for user.find() method like user.getById() but it gives the same error.
What might be causing this issue.
I was trying to get the thing shadow of a resource of aws iot in lambda function but the given code is giving null value on success instead of a data. Please let me know where is the problem and what changes should i do to make it work fine. Thanks in advance.
var AWS=require('aws-sdk');
var iotdata = new AWS.IotData({endpoint: 'XXXXXXXXX.iot.us-east-1.amazonaws.com'});
var params = {
thingName: 'thing_name' /* required */
};
exports.handler=function(event,context){
payload1=new Buffer(event.payload);
console.log(payload1);
iotdata.getThingShadow(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
context.succeed(data);
});
};
There are few places which need to be changed. Here is the new code:
getIotShadow: function (thingName) {
config.IOT_BROKER_ENDPOINT = "xxxxxxxxx.iot.us-east-1.amazonaws.com"; // also called the REST API endpoint
config.IOT_BROKER_REGION = "us-east-1"; // eu-west-1 corresponds to the Ireland Region. Use us-east-1 for the N. Virginia region
config.IOT_THING_NAME = thingName;
AWS.config.region = config.IOT_BROKER_REGION;
var iotData = new AWS.IotData({
endpoint: config.IOT_BROKER_ENDPOINT
});
var paramsGet = {
"thingName": config.IOT_THING_NAME /* required */
};
iotData.getThingShadow(paramsGet, function (err, data) {
if (err) {
console.log("Error : " + err, err.stack);
} else {
console.log(JSON.stringify(data));
}
});
}
I put my code into different modules:
.....
var util = require('util');
var s3 = new AWS.S3();
exports.perform_flatten = function(event, context) {
.......
CONTEXT = context;
s3_helper.get_object(SRC_BUCKET, SRC_KEY, this.flatten);
};
this.flatten is a callback to a module in the same file
exports.flatten = function(data){
.......
s3.putObject({Bucket: dst_bucket, Key: dst_key, Body: buffer}, function(err, data) {
if (err){
console.log(err, err.stack); // an error occurred
}else{
console.log(data); // successful response
CONTEXT.done();
}
});
}
The code runs perfectly until it comes to this line CONTEXT.done();.
Then I get the error: undefined is not a function
I do not understand why? Especially because I believe I declared CONTEXT as global right?
I have to call context.done() in order to execute a Lambda function on Amazon. http://docs.aws.amazon.com/lambda/latest/dg/programming-model.html THANKS