0

I can use this code to upload a single image to s3. When I try multiple, only the first item is uploaded and lambda stops executing. I'm new to javascript so I don't understand the problem here.

async function downloadImage(url) {
  var options = {
        uri: url,
        encoding: null
    };
  await new Promise((resolve, reject) => {
    request(options, function(error, response, body) {
        if (error || response.statusCode !== 200) { 
            console.log("failed to get image");
            console.log(error);
        } else {
            s3.putObject({
                Body: body,
                Key: 'template/'+url.split('/').pop(),
                Bucket: bucketName
            }, function(error, data) { 
                if (error) {
                    console.log("error downloading image to s3");
                } else {
                    console.log("success uploading to s3");
                }
            }); 
        }   
    });
  })
  .catch((error) => {
    console.log("error");
  });
}

exports.handler = async (event, _ctx, _cb) => {
  var images = {
    banner: "http://media.com/strip.png",
    icon: "http://media.com/icon.png",
    logo: "http://media.com/logo.png"
  }
  
  for (const [key, value] of Object.entries(images)) {
    console.log(`${key}: ${value}`);
    await downloadImage(value);
  }
}

The output I get from lambda for this:

2020-10-03T19:11:32.293Z    3cd401a6-08c6-49a2-b01c-99d6430ffc1a    INFO    banner: http://media.com/circle/strip.png
2020-10-03T19:11:33.201Z    3cd401a6-08c6-49a2-b01c-99d6430ffc1a    INFO    success uploading to s3
4
  • do not use async and await inside the downloadImage function as you have already used it in the handler, and after console.log("success uploading to s3"); write a return; Commented Oct 3, 2020 at 18:45
  • maybe the timeout of the lambda... Commented Oct 3, 2020 at 18:51
  • @Rolstan D'souza When I remove the async and await in the download function, the lambda outputs all three image keys and objects, but doesn't upload any image to s3 or show a success message Commented Oct 3, 2020 at 19:17
  • @Derek Menénedez The lambda stops execution after 900ms but the timeout is set to 3 minutes Commented Oct 3, 2020 at 19:18

1 Answer 1

1
const downloadImage = async url => {
  const options = {
    uri: url,
    encoding: null
  };
  const image = await requestPromise(options);
  await uploadToS3(image, url);
  return 'Uploaded'
}

const requestPromise = options => {
  return new Promise((resolve, reject) => {
    request(options, (error, response, body) => {
      if (error || response.statusCode !== 200) {
        console.log("failed to get image: ", error);
        return reject(error);
      }
      resolve(body);
    })
  })
}

const uploadToS3 = (body, url) => {
  return new Promise((resolve, reject) => {
    s3.putObject({
      Body: body,
      Key: 'template/' + url.split('/').pop(),
      Bucket: bucketName
    }, (err, data) => {
      if (err) {
        console.log("error downloading image to s3", err);
        return reject(err)
      };
      resolve(data);
    });
  })
}

exports.handler = async (event, _ctx, _cb) => {
  try {
    const images = {
      banner: "http://media.com/strip.png",
      icon: "http://media.com/icon.png",
      logo: "http://media.com/logo.png"
    }
    for (const [key, value] of Object.entries(images)) {
      console.log(`${key}: ${value}`);
      await downloadImage(value);
    }
  } catch (error) {
    console.log('Error in handler: ', error);
    return error
  }

}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for the solution. It works! Could you please kindly explain how this works or what I was doing wrong? Thank you
You are welcome! Your downloadImage is a very bad solution. Also, You don't have resolve/reject/return in there. So it won't work correctly. Your loop cant goes to the next iteration. Please mark the answer as useful if it is.
Thanks. Sorry, I don't have enough reputation to mark the answer as useful.
No problem! Don't worry!
A more typical approach would be to map over the images array and await Promise.all() on the resulting array of promises.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.