0

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"
    }
}
wawo
  • 37
  • 1
  • 8
  • Which AWS-SDK are you using? can you share your dependencies from pacakge.json ? – nirvana124 Apr 07 '21 at 10:10
  • @PankajYadav I've added them at the bottom – wawo Apr 07 '21 at 15:30
  • 1
    I am also having this issue. According to [this](https://stackoverflow.com/questions/43869401/amazons-aws-nodehttpclient-no-documentation) there isnt much documentation about AWS.HttpClient so I would recommend to try [this library](https://github.com/elastic/elasticsearch-js) instead – sivr Apr 08 '21 at 13:39

1 Answers1

1

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);
sivr
  • 101
  • 4
  • While I think it is important to know that there is no more support for this library (even though it is literally used as an example on the AWS webpage) as mentioned in your comment above, this workaround with some minor adjustments fixed it for me, thanks! – wawo Apr 08 '21 at 21:25