AWS S3 ListObjects in Node.js Lambda Function - node.js

I am attempting to list an S3 bucket from within my node.js (8.10) lambda function.
When I run the function below (in Lambda), I see "Checkpoint 1" and "Checkpoint 2" in my logs, but I don't see any logging from the listObjectsV2 call, neither error nor data. My timeout is set to 10 seconds and I am not seeing any log entries for timeouts, either. I think I may missing something about using asynchronous functions in lambda?
const AWS = require('aws-sdk');
const s3 = new AWS.S3({apiVersion: '2006-03-01'});
exports.handler = async (event, context) => {
// console.log('Received event:', JSON.stringify(event, null, 2));
var params = {
Bucket: 'bucket-name'
}
console.log("Checkpoint 1");
s3.listObjectsV2(params, function (err, data) {
if (err) {
console.log(err, err.stack);
} else {
console.log(data);
}
});
console.log("Checkpoint 2");
};
Can someone point me in the right direction for finding my error here?

Not only you need to return a promise, you also need to await on it, otherwise it has no effect. This is because your handler is async, meaning it will return a promise anyways. This means that if you don't await on the code you want to execute, it's very likely that Lambda will terminate before the promise is ever resolved.
Your code should look like this:
const AWS = require('aws-sdk');
const s3 = new AWS.S3({apiVersion: '2006-03-01'});
exports.handler = async (event, context) => {
// console.log('Received event:', JSON.stringify(event, null, 2));
var params = {
Bucket: 'bucket-name'
}
console.log("Checkpoint 1");
let s3Objects
try {
s3Objects = await s3.listObjectsV2(params).promise();
console.log(s3Objects)
} catch (e) {
console.log(e)
}
console.log("Checkpoint 2");
// Assuming you're using API Gateway
return {
statusCode: 200,
body: JSON.stringify(s3Objects || {message: 'No objects found in s3 bucket'})
}
};

AWS SDK can return a promise, just add .promise() to your function.
s3.listObjectsV2(params).promise();

Related

Inconsistent DynamoDB writtings

We have the following code used as lambda Function in Serverless Framework triggered every 2min with cron. The issue we are facing is that the writing in DynamoDB is inconsistent , we want to have 3 writings but instead we receive 1 or 2 writings every 2 minutes.
DynamoDB has a HASH key the HOUR and SORT KEY the DATE and Billing mode: PROVISIONED. Has someone faced the same behavior from DynamoDB or the same issue to share how he sovled it. Thanks
"use strict";
const AWS = require("aws-sdk");
const axios = require("axios");
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const lambda = new AWS.Lambda({
region: "us-east-1",
});
module.exports.getWeather = async (event, context, callback) => {
const openWeatherMapAPIURL = `http://api.openweathermap.org/data/2.5/weather?id=${event}&appid=XXXXXXXXXXXXXXXXXXXXXXX&units=metric`;
const currentWeather = await axios
.get(openWeatherMapAPIURL)
.then((records) => {
console.log(records);
const d = new Date(records.headers.date);
let hour = d.getHours();
const params = {
TableName: process.env.DYNAMODB_TABLE_NAME,
Item: {
hour: hour,
date: records.headers.date,
city: records.data.name,
temp: records.data.main.temp,
feelsLike: records.data.main.feels_like,
description: records.data.weather[0].description,
},
};
setTimeout(function () {
dynamoDb.put(params, (error) => {
// handle potential errors
console.log(`zapis na: ${records.data.name} ${records.headers.date}`);
if (error) {
console.log(error);
console.error(error);
return;
}
});
}, 3000);
})
.catch((error) => {
console.log(error);
return;
});
const response = {
statusCode: 200,
body: JSON.stringify({
message: `Weather from ${event} was requested!`,
}),
};
callback(null, response);
};
module.exports.cron_launcher = (event, context, callback) => {
const requestedID = ["786735", "792578", "785842"];
requestedID.forEach((requestedID) => {
const params = {
FunctionName: process.env.HANDLER_LOCATION + "-getWeather",
InvocationType: "RequestResponse",
Payload: JSON.stringify(requestedID),
};
return lambda.invoke(params, function (error, data) {
if (error) {
console.error(JSON.stringify(error));
return new Error(`Error printing messages: ${JSON.stringify(error)}`);
} else if (data) {
console.log(data);
}
});
});
};
You are not waiting for the dynamodb.put operation to finish. Additionally, you are wrapping the call in a setTimeout. Your lambda function is returning before the network operation can be made. Make sure the put operation succeeds before returning a result from your lambda.
I see no reason for you to use a setTimeout here.
You can call dynamodb.put(...).promise() to get a promise from the dynamodb SDK and await that promise.
2.a Or you can continue using a callback, but wrap the entire section of code in a new promise object, calling the resolve method after the dynamodb.put call finishes.

AWS Lambda to list S3 buckets with listBuckets() has no effect

I am new to writing Lambda in JS. I want to be able to list the S3 buckets I have, however, below lambda doesn't return what I expect, ie. list of buckets.
What have I done wrong? The only thing I am aware of is the line "console.log('hihi')" didn't print in my Cloudwatch log, so something going on when listBuckets() is invoked but I can't see any relevant logs... Tks in advance for any help !!
var AWS = require('aws-sdk');
AWS.config.update({region: 'us-east-1'});
exports.handler = async (event) => {
// Create S3 service object
var s3 = new AWS.S3({apiVersion: '2006-03-01'});
var params = {};
// Call S3 to list the buckets
s3.listBuckets(params, function(err, data) {
console.log('hihi')
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Buckets);
}
});
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
You are using async handler. Therefore, to your lambda does return before listBucket has a chance to execute. One way to overcome is through a Promise as shown in AWS docs.
Therefore, you could modify your code as follows:
var AWS = require('aws-sdk');
AWS.config.update({region: 'us-east-1'});
exports.handler = async (event) => {
const promise = new Promise(function(resolve, reject) {
// Create S3 service object
var s3 = new AWS.S3({apiVersion: '2006-03-01'});
var params = {};
// Call S3 to list the buckets
s3.listBuckets(params, function(err, data) {
console.log('hihi')
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Buckets);
}
});
})
return promise
};

Listing cognito userpool users on AWS lambda

I'm trying to list all of my cognito users in my lambda function, however i get nothing in the return as if the callback not getting executed. What am I doing wrong?
The output of the code below just gives me a hello in the console.
var AWS = require("aws-sdk");
const cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
export async function main() {
console.log("hello")
var params = {
UserPoolId: "myuserpoolid",
AttributesToGet: ["username"]
};
cognitoidentityserviceprovider.listUsers(params, (err, data) => {
if (err) {
console.log(err, err.stack);
return err;
} else {
console.log(data);
return data;
}
});
}
First of all, the structure of the code is wrong. The header of Lambda function should have a certain structure, either using async function or non-async function. Since you are using non-async code in your example I will show you how to do the later.
var AWS = require("aws-sdk");
const cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
exports.handler = function(event, context, callback) {
console.log("hello")
var params = {
UserPoolId: "myuserpoolid",
AttributesToGet: ["username"]
};
cognitoidentityserviceprovider.listUsers(params, (err, data) => {
if (err) {
console.log(err, err.stack);
callback(err) // here is the error return
} else {
console.log(data);
callback(null, data) // here is the success return
}
});
}
In this case, Lambda will finish only when callback is called (or when it times out).
Similarly, you can use async function but you will need to restructure your code accordingly. Here is an example taken from official docs. Note how the promise wrapper is used.
const https = require('https')
let url = "https://docs.aws.amazon.com/lambda/latest/dg/welcome.html"
exports.handler = async function(event) {
const promise = new Promise(function(resolve, reject) {
https.get(url, (res) => {
resolve(res.statusCode)
}).on('error', (e) => {
reject(Error(e))
})
})
return promise
}
For AttributesToGet, don't use username because it is one of the fields that always gets returned. The following are members of the Attributes array, and can be used in the AttributesToGet field:
sub, email_verified, phone_number_verified, phone_number, email.
e.g.
AttributesToGet: ["email","email_verified"]

Promise not executing when wrapped in a function

I am new to NodeJS and i am trying to post a message to AWS SNS from lambda. I took the code from AWS code samples and it is working fine in lambda.
But when i wrapped the same code in a function aand invoked from the main handler it is not working..
I tried returning and resolving the promise but nothing works.
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
exports.handler = async (event, context) => {
saveToSNS();
};
function saveToSNS() {
console.log("sdsdsd");
var AWS = require('aws-sdk');
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: '<MY TOPIC>'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
return publishTextPromise.then(
function(data) {
console.log("sdsdsd");
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
}
You need to place all code inside the handler as well. You can try like this:
exports.handler = async (event, context) => {
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'REGION'});
saveToSNS();
function saveToSNS() {
// Create publish parameters
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: 'TOPIC_ARN'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
publishTextPromise.then(function(data) {
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(function(err) {
console.error(err, err.stack);
});
}
};
You can either use async/await like this:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
exports.handler = async (event, context) => {
await saveToSNS();
};
async function saveToSNS() {
console.log("sdsdsd");
var AWS = require('aws-sdk');
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: '<MY TOPIC>'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
return publishTextPromise.then(
function(data) {
console.log("sdsdsd");
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
}
or add the return statement before calling saveToSNS() function, like this:
exports.handler = async (event, context) => {
return saveToSNS();
};

Read dynamodb code not being executed in exports.handler in lambda function

I have a lambda function written in node.js that returns a QRCode Image. I am also trying to read a value from the Dynamodb. However, the console logs inside it do not seem to be executed which makes me think the code is not being run.
I suspect this is due to so synchronization issues. But I am not sure what to do to fix it. The code is below:
var qrImage = require('qr-image');
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region:'us-west-2'});
exports.handler = async(event, context, callback) => {
var path = event.path;
var drugId = path.replace(/\//g, '');
var params = {
TableName: 'QRCodeInfo',
Key: {
"DrugId" : "1234"
}
};
docClient.get(params, function(err,data) { //does not get executed
if (err) {
console.log(err);
} else {
console.log(data);
}
});
return sendRes(200,drugId); //this works. Image is seen.
};
const sendRes = (status, body) => {
//console.log(body);
const svg_string = qrImage.imageSync(body, { type: 'svg', size: 10 });
var response = {
statusCode: status,
headers: {
"Content-Type": "image/svg+xml"
},
body: svg_string
};
return response;
};
You are probably exiting the lambda before the callback of the dynamodb call has had a chance to execute.
Try calling callback(null, data) in the callback of the dynamo call, after your console.log and similar in the err scenario e.g. callback(err)
You do not exit a lambda by calling return, you should be calling callback() (that's why it's available as the 3rd argument of the lambda) see https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html#nodejs-prog-model-handler-callback

Resources