Search code examples
node.jsamazon-web-servicesaws-lambdaaws-sdk-jsaws-elasticsearch

Not going into AWS HttpClient.handleRequest to elasticsearch in lambda, Nodejs


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"
    }
}

Solution

  • 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);