below is the code I'm trying to test by passing "type" property as "all". However, the returned data is null. The role set to this lambda is also given appropriate access to DB. There is data in the table as well.
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({ region: 'us-east-2', apiVersion: '2012-08-10' });
exports.handler = async (event, context, callback) => {
// TODO implement
const type = event.type;
if(type === "all"){
const params = {
TableName: 'compare-yourself'
};
dynamodb.scan(params, function(err, data){
if(err){
console.log(err);
callback(err);
} else {
console.log(data);
console.log(type);
callback(null, data);
}
});
} else if(type === "single") {
console.log(type);
callback(null, "Just my Data");
} else {
callback(null, "Hello from Lambda!");
}
};
I added a promise resolve rejection against the scan function and it resolved with a null always. When I removed the same, it worked fine.
This question is old, but I recognize the code. It's from the Udemy course on AWS by Maximilian Schwarzmüller.
If you come here with the same question, to implement the DynamoDB scan function in that course today, with newer versions of nodejs, use a promise and place the dynamodb.scan in a try catch. This code is in the Q&A section of that course under the title "I'm not able to get data".
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({ region: 'us-east-2', apiVersion: '2012-08-10' });
exports.handler = async (event, context, callback) => {
const type = event.type;
if (type === 'all') {
const params = {
TableName: 'compare-yourself'
}
try {
const data = await dynamodb.scan(params).promise()
callback(null, data)
} catch(err) {
callback(err);
}
} else if (type === 'single') {
callback(null, 'Just my data');
} else {
callback(null, 'Hello from Lambda');
}
};
Related
I want to achieve something like this:
call my website url https://mywebsite/api/something
then my next.js website api will call external api
get external api data
update external api data to mongodb database one by one
then return respose it's status.
Below code is working correctly correctly. data is updating on mongodb but when I request to my api url it respond me very quickly then it updates data in database.
But I want to first update data in database and then respond me
No matter how much time its take.
Below is my code
export default async function handler(req, res) {
async function updateServer(){
return new Promise(async function(resolve, reject){
const statusArray = [];
const apiUrl = `https://example.com/api`;
const response = await fetch(apiUrl, {headers: { "Content-Type": "application/json" }});
const newsResults = await response.json();
const articles = await newsResults["articles"];
for (let i = 0; i < articles.length; i++) {
const article = articles[i];
try {
insertionData["title"] = article["title"];
insertionData["description"] = article["description"];
MongoClient.connect(mongoUri, async function (error, db) {
if (error) throw error;
const articlesCollection = db.db("database").collection("collectionname");
const customQuery = { url: article["url"] };
const customUpdate = { $set: insertionData };
const customOptions = { upsert: true };
const status = await articlesCollection.updateOne(customQuery,customUpdate,customOptions);
statusArray.push(status);
db.close();
});
} catch (error) {console.log(error);}
}
if(statusArray){
console.log("success", statusArray.length);
resolve(statusArray);
} else {
console.log("error");
reject("reject because no statusArray");
}
});
}
updateServer().then(
function(statusArray){
return res.status(200).json({ "response": "success","statusArray":statusArray }).end();
}
).catch(
function(error){
return res.status(500).json({ "response": "error", }).end();
}
);
}
How to achieve that?
Any suggestions are always welcome!
Well, my lambda function work's well according to the log's, but it never get completed in the codepipeline stage, I have already set permission to role for allow notificate pipeline ("codepipeline:PutJobSuccessResult",
"codepipeline:PutJobFailureResult") and even set maximun time to 20sec but still not working (it actually ends at 800ms).
const axios = require('axios')
const AWS = require('aws-sdk');
const url = 'www.exampleurl.com'
exports.handler = async (event, context) => {
const codepipeline = new AWS.CodePipeline();
const jobId = event["CodePipeline.job"].id;
const stage = event["CodePipeline.job"].data.actionConfiguration.configuration.UserParameters;
const putJobSuccess = function(message) {
var params = {
jobId: jobId
};
codepipeline.putJobSuccessResult(params, function(err, data) {
if (err) {context.fail(err); }
else {context.succeed(message);}
});
};
const putJobFailure = function(message) {
var params = {
jobId: jobId,
failureDetails: {
message: JSON.stringify(message),
type: 'JobFailed',
externalExecutionId: context.invokeid
}
};
codepipeline.putJobFailureResult(params, function(err, data) {
if (err) console.log(err)
context.fail(message);
});
};
try {
await axios.post(url, { content: stage})
putJobSuccess('all fine')
} catch (e) {
putJobFailure(e)
}
};
The root issue
Because nodeJS runs everything async by default, codepipeline.putJobSuccessResult is being run async. The issue seems to be that the Lambda function is finishing it's execution before codepipeline.putJobSuccessResult has a chance to complete.
The solution
Run codepipeline.putJobSuccessResult synchronously so that it is forced to complete before the response is returned to Lambda for the lambdaHandler.
const putJobSuccess = function(id) {
//await sleep(60);
console.log("Telling Codepipeline test passed for job: " + id)
var params = {
jobId: id
};
return codepipeline.putJobSuccessResult(params, function(err, data) {
if(err) {
console.error(err)
} else {
console.log(data)
}
}).promise()
};
exports.lambdaHandler = async (event, context) => {
...
await putJobSuccess( jobId )
return response
};
Whenever I see this issue, most of the time it is due to 'PutJobSuccessResult' never being invoked. The best way to check this is to go to CloudTrail > 'Event History' and look for 'Event name' = 'PutJobSuccessResult' during the time range you expect the Lambda function calling this API. Probably you will not find the 'PutJobSuccessResult', then please have a look at the code again and the Lambda execution logs in CloudWatch.
I am new to async functions and promises. I have written a Lambda function which queries a DynamoDB table and returns the result. The code is executing inside the callback success block and I am able to see the response in the log from the console.log(res) line. However the Lambda response is always showing as null, i.e. the response object below is not returned at all. I was able to make this work using a Synchronous Lambda function using a callback to return the data. Can you please suggest what I may be doing incorrectly.
const doc = require('dynamodb-doc');
var dynamodbclient;
const tablename = process.env.TABLE_NAME;
exports.handler = async(event) => {
if (!dynamodbclient) {
dynamodbclient = new doc.DynamoDB();
}
let id = event.params.id;
let queryparams = {
TableName: 'table-name',
Key: { id: id }
};[![enter image description here][1]][1]
var getItemsCallback = (err, res) => {
console.log('inside');
if (err) {
}
else {
console.log('success');
console.log(res);
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
}
};
var item = await dynamodbclient.getItem(queryparams, getItemsCallback).promise();
};
Your callback is still executing after the promise resolves, so the lambda will terminate and your callback will not finish.
Try:
try {
const item = await dynamodbclient.getItem(queryparams).promise();
} catch (err) {}
console.log('success');
console.log(item);
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
I have written my first Lambda to handle an Alexa Skill.
My problem is that the call to the database is clearly asynchronous (I can tell from the order the Console.log messages appear in the Cloud Log.
Here is my Handler.
How do I make it so the return happens after the data is got from the database?
const RemindMeHandler = {
canHandle(handlerInput) {
const request = HandlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest'
|| (request.type === 'IntentRequest'
&& request.intent.name === 'RemindMeIntent');
},
handle(handlerInput) {
console.log('Started Reminder');
var thing="Nothinbg";
/* ========== Read dB ========== */
const params =
{
TableName: 'ItemsToRecall',
Key: {
'Slot': {S: '1'}
},
};
readDynamoItem(params, myResult=>
{
console.log('Reminder Results: ' + myResult.data);
thing="Captain";
console.log('thing 1: ' + thing);
});
console.log('Ended Reminder');
function readDynamoItem(params, callback)
{
var AWS = require('aws-sdk');
AWS.config.update({region: 'eu-west-1'});
var docClient = new AWS.DynamoDB();
console.log('Reading item from DynamoDB table');
docClient.getItem(params, function (err, data)
{
if (err) {
callback(err, data);
} else {
callback('Worked', data);
}
});
}
/* ========== Read dB End ========== */
console.log('thing 2: ' + thing);
return handlerInput.responseBuilder
.speak(REMINDER_ACKNOWLEDGE_MESSAGE + thing)
.getResponse();
}
};
/* ========== Remind Handler End ========== */
You can wrap the asynchronous and return a promise and then use async/await syntax to get the data. You can check the below. Do note it's not tested.
const RemindMeHandler = {
canHandle(handlerInput) {
return (
handlerInput.requestEnvelope.request.type === "LaunchRequest" ||
(handlerInput.requestEnvelope.request.type === "IntentRequest" &&
handlerInput.requestEnvelope.request.intent.name === "RemindMeIntent")
);
},
async handle(handlerInput) {
console.log("Started Reminder");
let thing = "Nothinbg";
const params = {
TableName: "ItemsToRecall",
Key: {
Slot: { S: "1" }
}
};
const data = await readDynamoItem(params);
console.log("Reminder Results: ", data);
thing = "Captain";
let speechText = thing;
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.getResponse();
}
};
function readDynamoItem(params) {
const AWS = require("aws-sdk");
AWS.config.update({ region: "eu-west-1" });
const docClient = new AWS.DynamoDB();
console.log("Reading item from DynamoDB table");
return new Promise((resolve, reject) => {
docClient.getItem(params, function(err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
My lambda function uses the method
ddb.putItem(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log("SUBMITTED DATA"); // successful response
});
with my params being correctly formatted to my table. No error is shown in my logs, however "SUBMITTED DATA" does not appear in the logs either, and the data is not put into my DynamoDB table. Any idea on what might be causing this problem? Heres my complete function:
const TrackHabitIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'TrackHabitIntent';
},
handle(handlerInput) {
ddb.putItem(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log("SUBMITTED DATA"); // successful response
});
const speechText = "That's awesome! I'll add today to your streak of 4 days";
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Hello World', speechText)
.getResponse();
}};
exports.handler = function (event, context) {
if (!skill) {
skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
HelpIntentHandler,
HelpMeIntentHandler,
TrackHabitIntentHandler,
NewHabitIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
)
.addErrorHandlers(ErrorHandler)
.create();
}
return response;
};
Thanks
Please check this code to add data in dynamoDB that can help you.
let putParams = {
TableName: tableName,
Item: {
'Id': {
S: Id
},
'name': {
S: name
}
},
ConditionExpression: 'attribute_exists(Id)'
};
dynamoDb.putItem(putParams, function (err, data) {
if (err) {
console.log('failure:put data from Dynamo error', err);
reject(err);
} else {
console.log('success:put data from Dynamo data');
resolve(data);
}
});