I know this same question was basically asked and answered, however, trying to implement the answer did not get it to work. Here is the original question: AWS.HttpClient handleRequest is not working in AWS lambda
I tried putting async/await on multiple different portions of the request, but none of them worked as mentioned in one of the comments in the referred to link.
The situation is that I have a lambda function that listens for events in the S3 buckets, when an event happens it is supposed to index the documents in elasticsearch service. The issue happens when a the PUT request is sent to es. I have done the test event with an S3 bucket and it WORKS, but for some reason it will hang/not go into the handleRequest function when I run an actual event to my S3 bucket. Here is my code:
Index.js
const AWS = require('aws-sdk');
const s3 = new AWS.S3()
const elastic_client = require('elastic.js');
exports.handler = async (event, context) => {
const Bucket = event.Records[0].s3.bucket.name;
const Key = event.Records[0].s3.object.key;
const data = await s3.getObject({ Bucket, Key }).promise();
for (const quote_doc of data.Body) {
elastic_client.indexQuote(quote_doc);
}
}
elastic.js
var AWS = require('aws-sdk');
require('dotenv').config();
var region = process.env.AWS_REGION;
var domain = process.env.AWS_ELASTIC_DOMAIN;
function indexQuote(quote) {
var endpoint = new AWS.Endpoint(domain);
var request = new AWS.HttpRequest(endpoint, region);
var index = 'quotes';
var type = '_doc';
var id = quote.QuoteId;
request.method = 'PUT';
request.path += index + '/' + type + '/' + id;
request.body = JSON.stringify(quote);
request.headers['host'] = domain;
request.headers['Content-Type'] = 'application/json';
request.headers['Content-Length'] = Buffer.byteLength(request.body);
var credentials = new AWS.EnvironmentCredentials('AWS');
credentials.accessKeyId = process.env.AWS_ACCESS_KEY_ID;
credentials.secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
var signer = new AWS.Signers.V4(request, 'es');
signer.addAuthorization(credentials, new Date());
var client = new AWS.HttpClient();
client.handleRequest(request, null, function(response) { // Here is where it gets hung up
console.log(response.statusCode + ' ' + response.statusMessage); // Never outputs this
var responseBody = '';
response.on('data', function (chunk) {
responseBody += chunk;
});
response.on('end', function (chunk) {
console.log('Response body: ' + responseBody);
});
}, function(error) {
console.log('Error: ' + error);
});
}
The confusing part for me is that it works fine when i do a test event, and it works fine when I index it locally on my own computer, but then just doesn't go into the handleRequest. Any help/direction is appreciated, thank you.
Edit:
package.json
{
"dependencies": {
"aws-sdk": "*",
"aws-xray-sdk": "^3.2.0",
"dotenv": "^8.2.0"
}
}
Try wrapping the handleRequest function inside a Promise. Your function indexQuote() would look almost the same, but at the end it would return a Promise
function indexQuote(quote) {
...
return new Promise((resolve, reject) => {
client.handleRequest(request, null,
response => {
const { statusCode, statusMessage, headers } = response;
let body = '';
response.on('data', chunk => {
body += chunk;
});
response.on('end', () => {
const data = {
statusCode,
statusMessage,
headers
};
if (body) {
data.body = body;
}
resolve(data);
});
},
err => {
reject(err);
});
});
And then you can await and inspect the result:
const result = await indexQuote(quote);
console.log("Index result: " + result);