AWS Lambda using s3 getObject function nothing happening

BermudaLamb picture BermudaLamb · Dec 6, 2018 · Viewed 9.6k times · Source

This is the node.js code using the inline editor:

const AWS = require('aws-sdk');
const s3 = new AWS.S3();

console.log('Loading function');

exports.handler = async (event) => {
    // TODO implement
    var responseMsg = '';
    var bucket = '';
    var key = '';
    if ('Records' in event) {
        var s3Data = event.Records[0].s3;
        console.log('s3Data: ' + JSON.stringify(s3Data));
        bucket = s3Data.bucket.name;
        key = s3Data.object.key;
    }
    console.log('Bucket:' + bucket);
    console.log('Key:' + key);
    var params = { 
        Bucket: bucket,
        Key: key
    };
    console.log('Params:' + JSON.stringify(params));
    s3.getObject(params, function (err, data) {
       console.log('getObject');
       if (err) {
           console.log(err, err.stack);
           return err;
       } 
       responseMsg = data;
    });
    const response = {
        statusCode: 200,
        body: JSON.stringify(responseMsg),
    };
    return response;
};

I know that the key and bucket I'm testing with exists in my S3 console. I know that I can access the them using C# in LINQPad.

When I run this, I'm not getting any errors. I'm getting an empty string in the body of response, rather than the content of the object. I'm also not getting any log messages from within the s3.getObject.

Answer

Kalev picture Kalev · Dec 7, 2018

The call to s3.getObject is an asynchronous call. The execution of the code continues while the s3 code is run. You need to explicitly await for the call's promise to resolve.

This is how you would do that (note the change in the s3.getObject call):

const AWS = require('aws-sdk');
const s3 = new AWS.S3();

exports.handler = async (event) => {
    var params = { 
        Bucket: <bucket>,
        Key: <key>,
    };

    const data = await s3.getObject(params).promise();

    const response = {
        statusCode: 200,
        body: JSON.stringify(data),
    };
    return response;
};

You can use a try/catch block for error handling.

The important thing to understand here is the timing of the execution. The mainline code in your function is called sequentially when the lambda is invoked. The callback function that you pass to the s3.getObject call is called when a response from S3 arrives, long after your lambda had finished its execution.

Your return call is executed before the callback runs, and hence you see the result of JSON.strigify(responseMsg) where responseMsg holds the initial value you gave it, which is the empty string ''.