AWS IoT - Failed to invoke lambda function - amazon-web-services

I'm trying to get my IoT device to fire off a Lambda function. Been trying for a few hours to no avail.
My lambda function is simple:
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify(event.message),
};
return response;
};
I've setup my IoT rule to trigger the lambda function with SELECT * FROM 'iot/trigger-lambda'. When I publish a message to the iot/trigger-lambda topic from AWS IoT's Test functionality, the lambda function triggers successfully. But, when I publish my message from my device, I get the following error:
{
"ruleName": "ruleTriggerLambda",
"topic": "iot/trigger-lambda",
"cloudwatchTraceId": "xxx-yyy-zzz",
"clientId": "ABC123",
"base64OriginalPayload": "eydvcGVyYGTpb24nOiAncHV0T2JqZWN0JywgJ2J1Y2tldCc6ICdyZWR3YXZlLWFwcC1kZXYnLCAna2V5JzogJ3JlYWNoYmFjay56aXAnLQWncmVwbHlUbyc6ICdpb3QvdGhyGHT0aWQtMDAwMS9wcmUtc2lnbmVkLBNzLXVybC1yBBNwb25zZXMnfSBbMV0=",
"failures": [
{
"failedAction": "LambdaAction",
"failedResource": "arn:aws:lambda:us-east-1:xxx:function:lambdaTriggerLambda",
"errorMessage": "Failed to invoke lambda function. Received Server error from Lambda. The error code is 400"
}
]
}
When I added the lambda function to my rule, AWS indicated it would create the correction permissions. I've also tried updating the permissions of the lambda function.
Any suggestions on how to fix this? Any help/information is much appreciated.
Edit: after 4 hours or ripping my hair out
It turned out to be the format of the data that I was sending as a payload from my IoT device. Let me explain, if someone can tell me why this is, I'd love to know.
I was using my mac as my device and I implemented this code from the AWS IoT Python SDK. My message looked like this:
message = {"message": "test message"}
It seems like pretty straight forward json.
The code that is publishing the message looks like this:
mqtt_connection.publish(
topic=args.topic,
payload=args.message,
qos=mqtt.QoS.AT_LEAST_ONCE)
The payload being received at AWS IoT Core looked like this:
{'message': 'test message'} [1]
And was accompanied by an error message like so: We cannot display the message as JSON, and are instead displaying it as UTF-8 String.
I guess I'm a little dense for not connecting the dots but it turns out I had to do the following to my code:
mqtt_connection.publish(
topic=args.topic,
payload=json.dumps(args.message).replace("\"", '').replace("[1]", '').replace("'", '"'),
qos=mqtt.QoS.AT_LEAST_ONCE)
Hopefully this explanation will help someone in the future.

Related

How should I implement my lambda handler with my REST API gateway model using non- proxy lambda?

I am stuck on how I should begin my lambda handler that will read some data from dynamodb. I have defined my api gateway model with the requests and response models, therefore do I need to state any status codes in the lambda handler ? Do I use API gateway proxy response event ? Any code examples
in Java would be helpful.
My notes on what I should include in the lambda handler:
access DB
map over table
Find attribute
Return response to api ?
What am I missing ? Thank you.
If you decided to use a non-proxy Lambda integration then you need to define an integration response using a regex. Here is an example using nodeJS:
lambda regex
Normally i declare my error messages just like this:
const errorMessages = {
INTERNAL_SERVER_ERROR: {
message: "Internal server error!",
code: 500
},
ERROR_BODY_INVALID: {
message: "Invalid request body",
code: 400
}
};
Then throw an error like this
exports.handler = function(event, context, callback) {
try {
// do something
} catch (error) {
callback(JSON.stringify(errorMessages.INTERNAL_SERVER_ERROR));
};
}
When a lambda error regex matches then it's mapped to the configured response status code.
P.D. If you are using Java this method does not work and you need to use proxy integration

Lex: The server encountered an error processing lambda

I'm developing a chatbot on AWS Lex and I want to use Lambda function to branch my intent.
In order to do so, I created a Lambda as follows:
exports.handler = async (event) => {
console.log(event); //capture Lex params
/*
let { name, slots } = event.currentIntent
if(slots.MeetingType.toLowerCase() === 'on-line') {
return {
dialogAction: {
type: "ElicitSlot",
intentName: name,
slotToElicit: "InvitationLink",
slots
}
}
}
return {
dialogAction: {
type: "Delegate",
slots
}
}
*/
};
But as you can see, even when the function does nothing but log Lex output, I'm getting this error message in Lex:
An error has occurred: The server encountered an error processing the
Lambda response
Any help would be appreciated.
Because you are trying to build a Lex chatbot using JavaScript, please refer to this use case in the AWS SDK for JavaScript DEV Guide. It will walk you through this use case:
Building an Amazon Lex chatbot
Once you get this working, you can port the logic to a Lambda function.
Amazon Lex is giving you this error message because the Lambda function has failed during execution.
Enable CloudWatch logging for your Lambda function and check the logs after Lex has called it. The logs should provide you with more specific details about what's caused the code to break/fail. From there you should have a better idea of how to resolve the issue.
Feel free to post the output from the logs if you need more assistance with debugging the issue.

How can I get log content in AWS Lambda from Cloudwatch

I have this basic lambda that posts an image to a web server.
From the events in CloudWatch, I can log successfully anything that happens in that lambda function :
From this Log Group (the lambda function) I clicked on Stream to AWS Lambda, chose a new lambda function in which I expect to receive my logs and didn't put any filters at all so I can get all logs.
The Lambda is triggered properly, but the thing is when I persist what I received in the event and context objects, I have all CloudWatch log stream information but I don't see any of the logs.
What I get :
Do I need to specify a filter for me to see any logs at all? Because in the filter section if I don't put any filters and click on test filter, I get all the logs in the preview window which seems to mean it should send the whole logs to my Lambda function. Also, it looked to me the logs where that unreadable stream in AWSLogs and that it was in Base64 but didn't get any results trying to convert that.
Yes the logs are gzipped and base64-encoded as mentioned by jarmod.
Sample code in NodeJs for extracting the same in lambda will be:
var zlib = require('zlib');
exports.handler = (input, context, callback) => {
var payload = new Buffer(input.awslogs.data, 'base64');
zlib.gunzip(payload, function(e, result) {
if (e) {
context.fail(e);
} else {
result = JSON.parse(result.toString());
console.log(result);
}
});

Alexa Skill SDK : Requested skill's response error

I have followed a tutorial to get this working.
My Alexa skill is built with invocation, intents and utterances set up.
My Lambda function is set up.
My endpoints default region is:
arn:aws:lambda:us-east-1:(myID found in AWS Support Center ):function:myLearn
myLearn function in Lambda is set with Alexa Skills Kit which has my correct Skill ID copied from the skill.
My HelloIntent doesn't have a slot. I'm just trying to get a response from the invocation.
My code running node.js 6.10 with a handler called index.handler follows as this:
var Alexa = require("alexa-sdk");
var handlers = {
"HelloIntent": function () {
this.response.speak("Hello, It's Me.");
this.emit(':responseReady');
},
"LaunchRequest": function () {
this.response.speak("Welcome to my thing I got going on.");
this.emit(':responseReady');
}
};
exports.handler = function(event, context, callback){
var alexa = Alexa.handler(event, context);
alexa.registerHandlers(handlers);
alexa.execute();
};
I've read that there are issues with zips but I didn't upload anything - I just changed the default index.js file...and my handler isn't named anything different - it's index.handler.
When I run the test in the alexa console I get the ol:
"There was a problem with the requested skill's response"
My json output is null.
And when I go to my logs in Cloud Watch:
Unable to import module 'index': Error at Function.Module._resolveFilename
I did a search for this and many of the errors were how users uploaded the zips and there was a conflict with the handler name and js file.
It looks like you might have created the Lambda function from the AWS Console and not included the alexa-sdk. To fix this you can start by using one of the provided 'Alexa blueprints' that include the alexa-sdk then overwrite the code in the Lambda with your code. Or you can package your code in a .zip file that includes the alexa-sdk module and upload the package through the web console. Here is a video I did a while back that explains the issue https://youtu.be/cFzAIhsldbs - I'm pretty sure that's your problem. I hope this helps.
You can try using "speechOutput" variable to store your response and then use the emit function.

AWS SNS Java program to subscribe

I am publishing a String message as message payload using SNS notification from Raspberry Pi using Python program and I want to pass that message payload to a Lambda function.
I have configured the requirement in the SNS console on AWS i.e., I have created a topic and added the lambda function to its subscribers.
Now, I want to get that message payload in the lambda function. But I can't find any method that can help me do that. For example, something like getMessage or something similar to that.
So my questions are: Since I have configured the publishing and subscription on AWS, can I assume that the clients are connected and if I publish a message I should be getting that at the subscriber's end which is my lambda function here?
Also, what's the technique in which I can get the message payload in my lambda function?
I am adding the below as per cjwfuller's suggestion.
Below I have written down the method for publishing in Python
client_boto = boto3.client('sns', aws_access_key_id='###',
aws_secret_access_key='###', region_name='us-west-2')
REGION = 'us-west-2'
TOPIC = 'arn:aws:sns:us-west-2:***:topic_name'
MSG = ntpath.basename(f_string)
SUBJECT_boto = 'File Name'
pub =client_boto.publish(TopicArn = TOPIC, Message = MSG,
Subject=SUBJECT_boto)
I am writing the subscribing code in Java.
Since my lambda func is already subscribed to it on AWS console,
should my Java program include the subscription again or is there a
way to get the msg payload directly.
Which language are you writing the function in? JavaScript as an example:
exports.myHandler = function(event, context, callback) {
console.log("value1 = " + event.key1);
console.log("value2 = " + event.key2);
// ...
}
Source: http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
It's useful testing the sort of stuff in the AWS Lambda console before writing all the code.
Since I have configured the publishing and subscription on AWS, can I assume that the clients are connected
Clients aren't really "connected", they're simply subscribed to a topic.
publish a message I should be getting that at the subscriber's end which is my lambda function here?
Sounds like you're doing the right sort of thing - posting example code will help us come up with more precise answers.
On searching, I have found the class for SNSEvent which is, https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/SNSEvent.java
This Class contains all the methods related to and needed to get the message payload.
The Lambda function handler in Java goes something like this,
example;
public void handleRequest(SNSEvent input, Context context){
String this_takes_message=input.getRecords().get(0).getSNS().getMessage();
}