【问题标题】:DynamoDB PutItem not awaiting, or executing finally blocksDynamoDB PutItem 未等待或执行 finally 块
【发布时间】:2020-08-16 14:12:15
【问题描述】:

我的 Lambda 接收包含 ID 和地址的 SQS 消息。它解析出这些字段,并在 dynamo 表中更新与该 ID 关联的记录。

本次更新的参数包含以下逻辑

1.记录的id等于SQS发送的ID

2.SortKey 的值等于“null”(注意,null 是一个值为“null”的字符串)

3.用新地址更新地址字段

我发现此功能存在以下问题

  1. 函数未更新 DynamoDB 实例

  2. 我没有收到来自更新电话的任何反馈。查看代码有几个 console.logs 应该执行但不是。请参阅更新后的 Try,Catch,Finally 块。查看日志,您可以看到这些不会输出到控制台。这里有些不对劲。 finally 不执行看起来像未定义的行为,我唯一的猜测是没有等待对 dynamodb 的调用

我还需要实现以下功能。这是加分项,如果您知道如何操作,请随时发表评论!

目前更新只会将地址的字段名从一个值更改为另一个值。相反,我需要记录包含一组与该记录关联的地址。为此,我们需要实现以下逻辑

如果记录中不存在一组地址,则创建一个以地址为唯一元素的集合 如果学生记录中确实存在集合,请使用地址更新该集合。不应添加重复的地址

这个函数的代码如下。我还附上了此功能的最新 CloudWatch 日志,以及我尝试更新的记录(记录上的地址字段是手动添加的)。你会注意到在 console.log("starting upload") 之后我们没有得到任何 console.logs,并且在检查时 Promise 的状态是“PENDING”。我们也没有从 dynamodb 更新中得到任何反馈。目前该功能没有更新记录,也没有给我任何反馈,说明为什么它没有这样做。

const util = require('util')
const aws = require('aws-sdk');
const docClient = new aws.DynamoDB.DocumentClient();



exports.handler = async(event) => {

    event.Records.forEach(async record => {
        const { body } = record;
        const test = JSON.parse(body);
        console.log(test);
        const message = JSON.parse(test["Message"]);
        console.log(message);

        const id = message.id;
        const name = message.Name;
        const address = message.address;
        console.log("parameters parsed");
        console.log("record being processed is " + id);

        const params = {
            TableName: "My_Records",
            Key: {
                "ID": ":id",
                "SortKey": ":sortKey"
            },
            //KeyConditionExpression: 'SortKey = :sortKey',
            UpdateExpression: "set info.address = :address",
            ExpressionAttributeValues: {
                ':id': id,
                ':address': address,
                ':sortKey': "null"
            },
            ReturnValues: "UPDATED_NEW"
        };
        console.log(params)

        console.log("starting upload")
        try {
            let putObjectPromise = docClient.update(params).promise();
            console.log(util.inspect(putObjectPromise, {showHidden: false, depth: null}))
            putObjectPromise.then(function(data) {
                console.log("UpdateItem succeeded:");
            }).catch(function(err) {
                console.log("Unable to update item. Error JSON:" + err);
            }).finally(() =>
                console.log("done with upload")
            );
            return putObjectPromise
        }
        catch (err) {
            console.err(err)
        }

    });
};

此函数最近执行的 CloudWatch 日志

INFO {
Type: 'Notification',
MessageId: 'ID',
TopicArn: 'ARN',
Subject: 'DB updated',
SignatureVersion: '1',
INFO { id: '11111111', Name: 'Jerms Macgee', address: '102 homeslice lane' }
INFO parameters parsed
INFO record being processed is 11111111
INFO {
TableName: 'my_table',
Key: { ID: ':id', SortKey: ':sortKey' },
UpdateExpression: 'set info.address = :address',
ExpressionAttributeValues: {
':id': '11111111',
':address': '102 homeslice lane',
':sortKey': 'null'
},
ReturnValues: 'UPDATED_NEW'
}
INFO starting upload
INFO Promise { <pending> }
END RequestId

这是我希望更新的记录示例

{
  "address": "test",
  "SortKey": "null",
  "id": 11111111
  "name": James Mcgee
}

更新的记录应该是

{
  "address": "102 homeslice lane",
  "SortKey": "null",
  "id": 11111111
  "name": James Mcgee
}

对于奖励积分,我真的很想做类似的事情

{
  "address": {"102 homeslice lane"},
  "SortKey": "null",
  "id": 11111111
  "name": James Mcgee
}

其中地址是可以保存其他记录的集合

【问题讨论】:

    标签: javascript node.js promise aws-lambda amazon-dynamodb


    【解决方案1】:

    首先,forEach 不适用于 async/await 回调。来自https://codeburst.io/javascript-async-await-with-foreach-b6ba62bbf404的例子

    const waitFor = (ms) => new Promise(r => setTimeout(r, ms));
    [1, 2, 3].forEach(async (num) => {
      await waitFor(50);
      console.log(num);
    });
    console.log('Done');
    

    其次,如果你在 try/catch 块中包装了一个被拒绝的 Promise,并且该 Promise 已经设置了一个 .catch(),那么 catch 块将永远不会被执行。

    const waitFor = (ms) => new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(123);
        }, ms)
    });
    try {
        waitFor(2000).catch(e => { console.log(e) })
    } catch (error) {
        console.error('error');
    }
    

    【讨论】:

    【解决方案2】:

    你混淆了你的异步/承诺的东西。

    首先,event.Records.forEach 不会等待您传递给它的异步函数来解析,您可以将其更改为:

    await Promise.all(event.Records.map(async record => {
      ///... the rest of your function body
    });
    

    这样你的主处理函数实际上会等待它们全部解决。

    接下来,所有这些东西:

    try {
            let putObjectPromise = docClient.update(params).promise();
            console.log(util.inspect(putObjectPromise, {showHidden: false, depth: null}))
            putObjectPromise.then(function(data) {
                console.log("UpdateItem succeeded:");
            }).catch(function(err) {
                console.log("Unable to update item. Error JSON:" + err);
            }).finally(() =>
                console.log("done with upload")
            );
            return putObjectPromise
        }
        catch (err) {
            console.err(err)
        }
    

    很奇怪,您使用的是.then 和回调函数,但您处于异步函数中,因此您可以等待它们。例如:

    try {
            const putObjectResponse = await docClient.update(params).promise();
            console.log("UpdateItem succeeded:");
            console.log(JSON.stringify(putObjectResponse));
        }
        catch (err) {
            console.log("Unable to update item. Error JSON:" + err);
            console.err(err)
        }
     console.log("done with upload")
    

    通过等待update(params).promise(),返回值变成了promise解析的内容,而不是promise。如果 promise 被拒绝,它会被抛出并被你的 catch 块捕获。

    这也修复了您奇怪的日志消息,因为您现在记录的是来自 Promise 而不是 Promise 本身的解析值。

    【讨论】:

      猜你喜欢
      • 2014-09-12
      • 1970-01-01
      • 1970-01-01
      • 2018-10-28
      • 2015-01-09
      • 1970-01-01
      • 2022-12-05
      • 1970-01-01
      • 2020-12-12
      相关资源
      最近更新 更多