DynamoDB PutItem не ожидает или не выполняет окончательные блоки - PullRequest
0 голосов
/ 02 мая 2020

My Lambda принимает сообщение SQS, содержащее идентификатор и адрес. Он анализирует эти поля и обновляет запись, связанную с этим идентификатором, в динамической таблице.

Параметры этого обновления содержат следующие логи c

1.Где запись имеет идентификатор, равный идентификатору, отправленному SQS

2. И где SortKey имеет значение, равное «null» (обратите внимание, что null, в частности, является строкой со значением «null»)

3. Обновите поле адреса новым адресом

I'm Видя следующие проблемы с этой функцией

  1. Функция не обновляет экземпляр DynamoDB

  2. Я не получаю никакой обратной связи от обновления вызов. Просматривая код, есть несколько console.logs, которые должны выполняться, но не должны. См. Блок «Попробуй, поймай, наконец» после обновления. Просматривая журналы, вы видите, что они не выводятся на консоль. Здесь что-то не так. Окончательно не выполняющийся выглядит как неопределенное поведение, единственное, что я предполагаю, это то, что не ожидается ожидаемый вызов DynamodB

Мне также нужно реализовать следующую функциональность. Это бонусные баллы, если у вас есть идея, как это сделать, пожалуйста, не стесняйтесь комментировать!

В настоящее время обновление изменит только имя поля адреса с одного значения на другое. Вместо этого мне нужно, чтобы запись содержала набор адресов, связанных с этой записью. Для этого нам нужно реализовать следующую логику c

Если в записи не существует набора адресов, создайте набор с адресом в качестве единственного элемента. Если набор существует в записи студента Обновите этот набор с адресом. Не следует добавлять дубликаты адресов

Код этой функции приведен ниже. Я также приложил самый последний журнал CloudWatch для этой функции и запись, которую я пытаюсь обновить (поле адреса в записи было добавлено вручную). Вы заметите, что мы не получаем никаких console.logs после console.log («начальная загрузка»), и обещание имеет состояние «В ожидании», когда оно проверяется. Мы также не получаем никакой обратной связи от динамодного обновления. В настоящее время функция не обновляет запись и не дает никаких комментариев о том, почему она этого не делает.

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
}

, где address - это набор, который может содержать другие записи

Ответы [ 2 ]

2 голосов
/ 02 мая 2020

Во-первых, forEach не будет работать с асинхронным / ожидающим обратным вызовом. Пример из 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 и это обещание уже имеет набор .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');
}
1 голос
/ 03 мая 2020

Вы смешиваете свои асинхронные / обещанные вещи.

Во-первых, event.Records.forEach не будет ждать, пока разрешится передача функции asyn c, которую вы передаете ей, вы можно изменить его на:

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 и функции обратного вызова, но вы находитесь в asyn c функции, так что вы можете просто ждать их. Например:

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() возвращаемое значение становится тем, к чему относится обещание, а не обещанием. Если обещание отклоняется, оно выбрасывается и перехватывается в вашем блоке перехвата.

Это также исправляет ваши странные сообщения регистрации, поскольку теперь вы регистрируете разрешенное значение из обещания, а не самого обещания.

...