Я пытаюсь реализовать простой счетчик с помощью лямбда-функции, но всякий раз, когда я его тестирую, 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"
}
}
}



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это связано с асинхронным характером 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.
@ChuckAdams Я сомневаюсь, что примеры AWS здесь неверны, но я полагаю, что это возможно. Можете ли вы указать какие-либо примеры?
Я бы добавил, что примеры AWS не так уж неверны, я неправильно их прочитал, особенно теперь, когда вы указали на документы JS SDK, где прямо указано: «Все запросы, сделанные через SDK, являются асинхронными». Пример, который я искал в другом месте (который я не могу найти сейчас), был на Python, который я более или менее транслитерировал, используя другой пример JS в качестве руководства, и это, вероятно, не помогло ?
Большое спасибо за ответ и, в частности, за последнюю ссылку на документацию AWS. Я (в основном) получаю async/await, но все примеры API dynamodb, которые я видел в Интернете (включая собственную документацию AWS), делали его похожим на синхронную операцию.