1

I know this has been asked in various ways before, but I can't figure it out. I'm still very new to node.js and lambda. This code will work if I run the lambda twice, but never runs to completion the first time. This also works fine if I run this from a local IDE by adding exports.handler(); to the end of the code block.

The code queries DynamoDB for results and then attempts to delete those records from Dynamo. The query part seems to work every time, but the deletion part fails to happen on the first invocation. I can't seem to figure out what changes are necessary to for lambda to wait until all of my processes are complete.

Thanks in advance.

// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({ region: 'us-east-2' });
exports.handler = async (event) => {
    // Create DynamoDB service object
    const ddb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
    const documentClient = new AWS.DynamoDB.DocumentClient({ region: "us-east-2" });
    const tablename = process.env.table_name;

    let dynapromises = [];

    let params = {
        ExpressionAttributeValues: {
            ':offNum': { S: process.env.cost_center },
            ':s': { N: '2' }
        },
        ExpressionAttributeNames: {
            "#notif_status": "status"
        },
        KeyConditionExpression: 'officeNumber = :offNum',
        TableName: tablename,
        IndexName: 'officeNumberIndex',
        ProjectionExpression: "notificationNumber",
        FilterExpression: '(attribute_not_exists(#notif_status) or #notif_status = :s) and attribute_not_exists(statusTimes)'
    };

    let qresults = await ddb.query(params).promise();
    console.log("Count of notifs again " + qresults.Items.length);

    qresults.Items.forEach(function(element, index, array) {
        console.log(element.notificationNumber.S);
        let delparams = {
            TableName: tablename,
            ReturnValues: "ALL_OLD",
            Key: {
                notificationNumber: {
                    S: element.notificationNumber.S
                }
            }
        };

        dynapromises.push(ddb.deleteItem(delparams).promise().then(function(data) {
            console.log("Deleted Record:"+ JSON.stringify(data)); // successful response
        }, function(error) {
            console.log(error, error.stack); // an error occurred
        }));
        console.log("deletion parameters " + JSON.stringify(delparams));
    });
    Promise.all(dynapromises).then(res => {
        console.log("All promises done");
    });
    return qresults.Items.length;
};
1
  • Side note: I would clean up your code to consistently use either async/await or .then() everywhere + map() instead of push(): stackoverflow.com/a/31414472/65232 Commented Jan 21, 2020 at 16:05

2 Answers 2

1

The issue is in that you are returning before all the promises are completed, you need to move the return qresults.Items.length; inside the last then.

try with this code:

** UPDATE: Change the snippet with the working code **

// Load the AWS SDK for Node.js
const AWS = require('aws-sdk');
// Set the region
AWS.config.update({ region: 'us-east-2' });
exports.handler = async (event) => {
    // Create DynamoDB service object
    const ddb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
    const documentClient = new AWS.DynamoDB.DocumentClient({ region: "us-east-2" });
    const tablename = process.env.table_name;

    let params = {
        ExpressionAttributeValues: {
            ':offNum': { S: process.env.cost_center },
            ':s': { N: '2' }
        },
        ExpressionAttributeNames: {
            "#notif_status": "status"
        },
        KeyConditionExpression: 'officeNumber = :offNum',
        TableName: tablename,
        IndexName: 'officeNumberIndex',
        ProjectionExpression: "notificationNumber",
        FilterExpression: '(attribute_not_exists(#notif_status) or #notif_status = :s) and attribute_not_exists(statusTimes)'
    };

    let qresults = await ddb.query(params).promise();
    console.log("Count of notifs again " + qresults.Items.length);

    const dynapromises = qresults.Items.map( async element => {
    	let delparams = {
            TableName: tablename,
            ReturnValues: "ALL_OLD",
            Key: {
                notificationNumber: {
                    S: element.notificationNumber.S
                }
            }
        };

        try {
        	 console.log("deletion parameters " + JSON.stringify(delparams));
	        const data = await ddb.deleteItem(delparams).promise();
    	    console.log( "Deleted Record:"+ JSON.stringify(data) );
        } catch ( err ) {
        	console.log(error, error.stack); // an error occurred
        }
    } )

    await Promise.all(dynapromises)

    console.log("All promises done");
    return qresults.Items.length;
};

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

9 Comments

Thank you for the suggestion. I just tried with your modification and I'm still having the same results. It doesn't perform the deletions on the first invocation.
Hi RobCent, can you paste here the logs from the first invocation?
The logs are somewhat useless in this case. I don't want to copy/paste since there can potentially be real customer data in the logs, but I'll give you an idea of what the logs show. INFO Count of notifs again 43 INFO 400265091 INFO deletion parameters { "TableName": "NotificationTableQA", "ReturnValues": "ALL_OLD", "Key": { "notificationNumber": { "S": "400265091" } } } These are repeated for each dynamo result, then the logs just end with "END RequestId: XXXXXX"then the lambda report on duration etc No errors are in the logs.
thanks, but you see the lines Deleted Record:... inside the then?
The console.log statements like "Deleted Record:" or the error never show in the logs for the first invocation. Only when I rerun the lambda the second time do i get that.
|
0

The code that @pepo posted is performing the Dynamo deletions on the first invocation of the Lambda. Thanks for his work and the responses from everyone.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.