DynamoDB updateItem в Lambda молча терпит неудачу

Я пытаюсь реализовать простой счетчик с помощью лямбда-функции, но всякий раз, когда я его тестирую, updateItem ниже просто не работает: ни один из операторов журнала в обратном вызове вообще не выполняется, и, конечно, соответствующий счетчик в таблице никогда не обновляется. Вот моя лямбда-функция:

'use strict';
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });

let params = {
    TableName: 'Counters',
    Key: {
        'name': { S: 'global' }
    },
    UpdateExpression: 'SET val = val + :inc',
    ExpressionAttributeValues: {
        ':inc': { N: '1' }
    },
    ReturnValues: 'ALL_NEW'
};

exports.handler = async(event) => {
    console.info("Invoked counter-test");

    dynamodb.updateItem(params, function(err, data) {
        console.info("In updateItem callback");
        if (err)
            console.info(err, err.stack);
        else
            console.info(data);
    });

    console.info("Updated counter");

    const response = {
        statusCode: 200,
        body: JSON.stringify('Counter updated'),
    };
    return response;
};

И вот результат теста:

Response:
{
  "statusCode": 200,
  "body": "\"Counter updated\""
}

Request ID:
"80e92299-2eea-45e4-9c68-54ccf87199c5"

Function Logs:
START RequestId: 80e92299-2eea-45e4-9c68-54ccf87199c5 Version: $LATEST
2019-05-07T11:34:21.931Z    80e92299-2eea-45e4-9c68-54ccf87199c5    Invoked counter-test
2019-05-07T11:34:21.934Z    80e92299-2eea-45e4-9c68-54ccf87199c5    Updated counter
END RequestId: 80e92299-2eea-45e4-9c68-54ccf87199c5
REPORT RequestId: 80e92299-2eea-45e4-9c68-54ccf87199c5  Duration: 275.91 ms Billed Duration: 300 ms     Memory Size: 128 MB Max Memory Used: 67 MB  

Как видите, операторы журнала из обратного вызова updateItems не выполнялись.

Однако, если я попытаюсь обновить счетчик из командной строки с помощью aws dynamodb, он сработает:

$ aws dynamodb update-item \
  --table-name Counters \
  --key '{"name": { "S": "global" }}' \
  --update-expression 'SET val = val + :inc' \
  --expression-attribute-values '{":inc": {"N": "1"}}' \
  --return-values ALL_NEW \
  --output json
{
    "Attributes": {
        "name": {
            "S": "global"
        },
        "val": {
            "N": "129"
        }
    }
}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
1 271
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это связано с асинхронным характером Javascript.

Метод updateItem является асинхронным, и вы не ждете запуска обратного вызова перед возвратом (вы запускаете операцию updateItem и сразу же возвращаете ответ).

Если вы хотите сохранить шаблон обратного вызова, вы должны сделать:

exports.handler = (event, context, callback) => {
    console.info("Invoked counter-test");

    dynamodb.updateItem(params, function(err, data) {
        console.info("In updateItem callback");
        if (err) {
            console.info(err, err.stack);
            callback(err);
        } else {
            console.info(data);
            console.info("Updated counter");
            const response = {
                statusCode: 200,
                body: JSON.stringify('Counter updated'),
            };
            callback(null, response);
        }
    });
};

Использование обещаний:

exports.handler = (event, context, callback) => {
    console.info("Invoked counter-test");

    dynamodb.updateItem(params).promise()
        .then((data) => {
            console.info(data);
            console.info("Updated counter");

            const response = {
                statusCode: 200,
                body: JSON.stringify('Counter updated'),
            };
            callback(null, response);          
        });
        .catch((err) => {
          console.info(err, err.stack);
          callback(err);
        })
};

Использование await (рекомендуется):

exports.handler = async (event) => {
    try {
        console.info("Invoked counter-test");

        const data = await dynamodb.updateItem(params).promise();
        console.info(data);

        console.info("Updated counter");

        const response = {
            statusCode: 200,
            body: JSON.stringify('Counter updated'),
        };
        return response;      
    } catch (err) {
      console.info(err, err.stack);
      throw err;
    }
};

См. также Понимание асинхронного JavaScript, Глубокое понимание JavaScript Async и Await с примерами и AWS SDK для Javascript — использование промисов JavaScript.

Большое спасибо за ответ и, в частности, за последнюю ссылку на документацию AWS. Я (в основном) получаю async/await, но все примеры API dynamodb, которые я видел в Интернете (включая собственную документацию AWS), делали его похожим на синхронную операцию.

Chuck Adams 07.05.2019 15:29

@ChuckAdams Я сомневаюсь, что примеры AWS здесь неверны, но я полагаю, что это возможно. Можете ли вы указать какие-либо примеры?

jarmod 07.05.2019 15:41

Я бы добавил, что примеры AWS не так уж неверны, я неправильно их прочитал, особенно теперь, когда вы указали на документы JS SDK, где прямо указано: «Все запросы, сделанные через SDK, являются асинхронными». Пример, который я искал в другом месте (который я не могу найти сейчас), был на Python, который я более или менее транслитерировал, используя другой пример JS в качестве руководства, и это, вероятно, не помогло ?

Chuck Adams 07.05.2019 15:51

Другие вопросы по теме