Node.js - AWS - Program Terminates Before Upload t

2019-08-17 14:43发布

问题:

I've written a program that creates HTML files. I then attempt to upload the files to my S3 bucket at the end of the program. It seems that the problem is that my program terminates before allowing the function to complete or receiving a callback from the function.

Here is the gist of my code:

let aws = require('aws-sdk');

aws.config.update({
    //Censored keys for security
    accessKeyId: '*****',
    secretAccessKey: '*****',
    region: 'us-west-2'
});

let s3 = new aws.S3({
    apiVersion: "2006-03-01",
});

function upload(folder, platform, browser, title, data){
    s3.upload({
        Bucket: 'html',
        Key: folder + platform + '/' + browser + '/' + title + '.html',
        Body: data
    },  function (err, data) {
        if (err) {
            console.log("Error: ", err);
        }
        if (data) {
            console.log("Success: ", data.Location);
        }
    });
}

/*
*
* Here is where the program generates HTML files
*
*/

upload(folder, platform, browser, title, data);

If I call the upload() function (configured with test/dummy data) before the HTML generation section of my code, the upload succeeds. The test file successfully uploads to S3. However, when the function is called at the end of my code, I do not receive an error or success response. Rather, the program simply terminates and the file isn't uploaded to S3.

Is there a way to wait for the callback from my upload() function before continuing the program? How can I prevent the program from terminating before uploading my files to S3? Thank you!

Edit: After implementing Deiv's answer, I found that the program is still not uploading my files. I still am not receiving a success or error message of any kind. In fact, it seems like the program just skips over the upload() function. To test this, I added a console.log("test") after calling upload() to see if it would execute. Sure enough, the log prints successfully.

Here's some more information about the project: I'm utilizing WebdriverIO v4 to create HTML reports of various tests passing/failing. I gather the results of the tests via multiple event listeners (ex. this.on('test:start'), this.on('suite:end'), etc.). The final event is this.on('end'), which is called when all of the tests have completed execution. It is here were the test results are sorted based on which Operating System it was run on, Browser, etc.

I'm now noticing that my program won't to do anything S3 related in the this.on('end') event handler even if I put it at the very beginning of the handler, though I'm still convinced it's because it isn't given enough time to execute because the handler is able to process the results and create HTML files very quickly. I have this bit of code that lists all buckets in my S3:

s3.listBuckets(function (err, data) {
    if (err) {
        console.log("Error: ", err);
    } else {
        console.log("Success: ", data.Buckets);
    }
});

Even this doesn't return a result of any kind when run at the beginning of this.on('end'). Does anyone have any ideas? I'm really stumped here.

Edit: Here is my new code which implement's Naveen's suggestion:

this.on('end', async (end) => {

/*
* Program sorts results and creates variable 'data', the contents of the HTML file.
*/

    await s3.upload({
        Bucket: 'html',
        Key: key,
        Body: data
    }, function (err, data) {
        if (err) {
            console.log("Error: ", err);
        }
        if (data) {
            console.log("Success: ", data.Location);
        }
    }).on('httpUploadProgress', event => {
        console.log(`Uploaded ${event.loaded} out of ${event.total}`);
    });
}

The logic seems sound, but still I get no success or error message, and I do not see the upload progress. The HTML file does not get uploaded to S3.

回答1:

You can use promises to wait for your upload function to finish. Here's what it will look like:

function upload(folder, platform, browser, title, data) {
    return new Promise((resolve, reject) => {
        s3.upload({
            Bucket: 'html',
            Key: folder + platform + '/' + browser + '/' + title + '.html',
            Body: data
        }, function(err, data) {
            if (err) {
                console.log("Error: ", err);
                return reject(err);
            }
            if (data) {
                console.log("Success: ", data.Location);
                return resolve();   //potentially return resolve(data) if you need the data
            }
        });
    });
}

/*
*
* Here is where the program generates HTML files
*
*/

upload(folder, platform, browser, title, data)
    .then(data => { //if you don't care for the data returned, you can also do .then(() => {
        //handle success, do whatever else you want, such as calling callback to end the function
    })
    .catch(error => {
        //handle error
    }