Will AWS Lambda wait for my response? - node.js

I'm using AWS lambda as SQS listener in my project. Some time no response got in my log, most of the time it's working.
code
console.log('Befor Req ' + post_data);
// Set up the request
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function (response) {
console.log('Request data' + post_data);
console.log('Response ' + response);
});
res.on('error', function (err) {
console.log(err);
})
});
// post the data
post_req.write(post_data);
post_req.end();
Here I got all fine in before request, sometimes the log inside the request not get logging.
I check the other side request and response are logged and all fine.
Is this any specific issue with AWS LAMBDA?

The log inside the request is an asynchronous callback's either log inside your on success or your failure callback should prints.
If not There are two posibilities.
one is you are terminating lambda before that async code completed
posibility no 2 is, your lambda got timesout before that async request completed . see this scenario may works on sometime and fails on other time. It depends on our async execution time and lambda timeout
TO ensure this check your cloudwatch log for lines task timedout after x second. And you will be get 502 on that time if you are using lambda proxy in API gateway. see below

Related

Make POST https request in AWS Lambda without waiting for response

I am trying to make an https request (API gateway call to other Lambda) in my AWS Lambda function with Node.js, but without waiting for the response, so when the data has already been sent to the other Lambda (and starts running), my first Lambda stops running.
What I've been trying to do is the following code:
await new Promise((resolve, reject) => {
const options = {
hostname: 'example.com',
path: '/example/action',
method: 'POST'
}
const req = https.request(options);
console.log('Request: ', req);
req.on('error', error => {
reject(error);
});
// Send data
req.write(JSON.stringify(data));
req.end(() => {
// This is where (in theory) request has been made, and no response received
resolve(req);
});
});
It results in a timeout issue, due to resolve is never called.
Any ideas?

How to asynchronously make HTTP Requests in AWS Lambda Node.js runtime

I have created an API endpoint that returns an integer when it is successfully accessed with an HTTP Post request. I want an AWS CloudWatch scheduled process to run an AWS Lambda function every minute to check the API endpoint so make sure the value is not zero. I have set up the scheduled AWS CloudWatch process and the AWS Lambda function, where the runtime is Node.js 10. However, when I look at the AWS CloudWatch group's stream log, the logs seem to be out of order. I suspect this is because of the HTTP Request to the API endpoint is running asynchronously, but I ultimately do not know. The time that it takes to log the value of this HTTP Request to the API end point seems to be much longer than the actual time to process the request.
Here is the Node.js lambda function that is being run on a minutely basis:
exports.handler = async (event) => {
var datetime = new Date();
var request = require("request");
var options = {
method: 'POST',
url: 'https://website.com/api/getDataPoints',
headers:
{
'cache-control': 'no-cache',
'content-type': 'text/plain'
},
body: '{"token" : "yT7g8urUFmEZwQrJNHgQGRDA9zScpNzPM3rb"}'
};
await request(options, function (error, response, body) {
if (error)
{
throw new Error(error);
// Email and SMS message that this is having an error
}
if (body == 0)
{
// Email and SMS message that this is having an error
// Restart EC2 server
}
console.log(datetime.toString() + " - " + body + " Data Points!");
});
};
Here is the AWS CloudWatch log, where it's easier to see the delay in logging the response from the HTTP Request:
Any insight into the cause of this perceived log delay or suggestions on how to achieve similar results in a more efficient way would be greatly appreciated! Thank you!
Here is what is happening: the await is returning immediately because the request function does not return a promise, so the callback is happening after the lambda function exits. The reason why there is such a long delay in seeing the log is that when your lambda function becomes idle (meaning all handler functions have returned, even if there are callbacks waiting) AWS can suspend any executing code until a new invocation of the function. So in your case when the next minute rolls around and the lambda function is invoked again, AWS will un-suspend any executing code and the callback kicks off immediately and you see the log for the previous invocation.
To solve this you want to make sure the handler function doesn't return until all work has been completed (which is what I think you were intending to do with the await). So wrap the request call in a function that returns a promise which is resolved in the callback and use await on the wrapper function.
function doRequest() {
return new Promise((resolve, reject) => {
request(options, function (error, response, body) {
if (error){
throw new Error(error);
// Email and SMS message that this is having an error
}
if (body == 0){
// Email and SMS message that this is having an error
// Restart EC2 server
}
console.log(datetime.toString() + " - " + body + " Data Points!");
resolve();
});
});
}
await doRequest();

Node.js socket hang up with http.get but not with request module

I am performing some http calls in an AWS lambda. The number of calls are ~400 per minute.
The calls are performed as in the following snippet
var req = http.get("https://www.google.com", res => {
let body = '';
res.on('data', chunk => {
body += chunk;
});
res.on('end', chunk => {
if (body.includes('html')) {
console.log('Got back healthy response');
} else {
console.log('Got an unexpected response');
}
})
});
req.on('error', e => {
console.log('Got an error response');
})
That is a simple https request. When the Lambda is invoked, it performs ~40 requests in a single execution.
My issue is that at the beginning, everything looks good and all the requests are performed correctly. After a while (that can be after ~30 min) calls start to degrade and I get back "socket hang up ECONNRESET" error.
I then tried using the request module and change the code with the following
const request = require('request');
request("https://www.google.com", function (error, response, body) {
if (!error && response.statusCode == 200 && body.includes('html')) {
console.log('Got back healthy response' );
} else {
console.log('Got an unexpected response');
console.log('Error: ' + error);
console.log('Response: ' + response);
console.log('Body: ' + body);
}
});
In this case, with the same number of requests within the same lambda, same setting I never get the ECONNRESET error.
I'm ok using the request module but I'm curious to know why this was happening with the default http implementation.
Is this caused by socket allocation that the request module handles in a more appropriate way?
I know similar questions have been asked already but I didn't find a good answer for my case.
This isn't really an answer but I cannot write comments.
The main difference I can see is the encoding. The default encoding in request is utf8, whereas in the http module it's buffer. Adding res.setEncoding('utf8'); might be helpful. It might not be faster. In the line body += chunk you just implicitly convert a Buffer to a string so it should be the same.
If adding the setEncoding won't change anything then you might want to report an issue to the nodejs team because it's the same as the example in http_http_get_url_options_callback. They should fix it or change the example.

HTTP request issue Internal Server error

I am having issues with an HTTP response giving me a status code: 502, and error message: Internal Server Error. My setup is an AWS Lambda written in NodeJS making an HTTPS POST request to an AWS API Gateway integrated with another Lambda, as its backend.
The strange part is the Lambda acting as the backend of the API receives all the POST requests just fine and is able to execute its functions perfectly, but its callback responds to the other Lambda with an error.
Below is the callback on the lambda on the API Gateway side
const done = (err, res) => callback(err, {
statusCode: err ? JSON.stringify(err.code) : '200',
body: err ? JSON.stringify(err.message) : JSON.stringify(res),
headers: {
'Content-Type': 'application/json',
}
});
And here is the code from the other lambda making an https POST request
const req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
process.stdout.write(d);
});
res.on('end', function () {
console.log(JSON.stringify(body));
});
});
req.on('error', (e) => {
console.error(e);
console.log("request error");
});
req.write(JSON.stringify(payload));
console.log("req.end");
req.end();
I feel the problem is in these blocks of code because if I change the callback of the Lambda integrated API Gateway to hardcode the response to a 200 status code, then everything works fine.
Problem I see with your code is, if err.code is empty or invalid value, then you will get 502 on API Gateway. You need to fix the code so that it sends back a valid http response with a valid status code.
If your status code is invalid or empty then it will throw a 502 to the caller since the http response from lambda is invalid.
Hope it helps.
Problem is fixed now. No code changes were necessary but the problem was that the Lambda's Node.Js source files on the API Gateway side needed to be zipped with the necessary dependencies or node_modules as explained here http://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html
I was facing a similar problem of getting Internal server error while calling external API from lambda function.
Earlier time out for lambda function was 6sec and I increased to some 25sec. After that everything works fine.
Nodejs is asynchronous before getting API response next lines were executing irrespective of using async await.

How to send http request with nodejs AWS Lambda?

I'm using AWS Lambda to drive an Alexa Skill Kit development. In an attempt to track events, I'd like the script to send an HTTP request on launch, however from the cloud logs it appears as though the http.get function is being skipped during the execution process.
The code is shown below (google.com replaces the analytics tracking url - which has been tested in the browser);
exports.handler = function (event, context) {
var skill = new WiseGuySkill();
var http = require('http');
var url = 'http://www.google.com';
console.log('start request to ' + url)
http.get(url, function(res) {
console.log("Got response: " + res.statusCode);
// context.succeed();
}).on('error', function(e) {
console.log("Got error: " + e.message);
// context.done(null, 'FAILURE');
});
console.log('end request to ' + url);
skill.execute(event, context);
};
The context objects have been commented out to allow for 'skill.execute' to function, yet either way this HTTP request is not executing. Only the 'start' and 'end' console.logs are recorded, those internal in the function do not.
Is this a async issue? Thanks.
You need to make sure the handler is being triggered. There are two ways of accomplishing this:
You could set up a new API endpoint and execute a request on that.
You could hit the Test button and your function would be invoked with the given data.
I copied and pasted your whole snippet except for the first and the last lines (because I don't have customSkill defined anywhere). I was able to get a 200 response code.
In order to successfully complete the http request, the http.get function must be incorporated into a callback function. Else the process will not be completed and will end prematurely, using a callback allows the http request to complete (with or without an error) before continuing with the rest of the function.
WiseGuySkill.prototype.eventHandlers.onLaunch = function (launchRequest, session, response) {
// Call requestFunction to make the http.get call.
// Get response from requestFunction using requestCallback
requestFunction(function requestCallback(err) {
// If error occurs during http.get request - respond with console.log
if (err) {
console.log('HTTP Error: request not sent');
}
ContinueIntent(session,response);
});
};
The function 'requestFunction' calls http.get and fires the callback.
function requestFunction(requestCallback){
var url = "http://www.google.com";
http.get(url, function(res) {
console.log("Got response: " + res.statusCode);
requestCallback(null);
}).on('error', function (e) {
console.log("Got error: ", e);
});
}
And obviously ensure you have required 'http' at the start of the script.
Hope this helps anybody else new to this!

Resources