Запрос DynamoDB с Lambda ничего не делает

У меня есть следующий код для функции лямбда:

console.log('Loading function');
var aws = require('aws-sdk');
var ddb = new aws.DynamoDB();

function getUser(userid) {
    var q = ddb.getItem({
        TableName: "Users",
        Key: {
            userID: { S: userid } }
        }, function(err, data) {
            if (err) {
                console.log(err);
                return err;
            }
            else {
                console.log(data);
            }
    });
    console.log(q);
}


exports.handler = function(event, context) {
    console.log('Received event');
    getUser('user1');
    console.log("called DynamoDB");
    context.succeed();
};

У меня есть таблица [Users], которая определяется как таковая:

{
    "cognitoID": { "S": "token" },
    "email": { "S": "[email protected]" },
    "password": { "S": "somepassword" },
    "tos_aggreement": { "BOOL": true },
    "userID": { "S": "user1" }
}

Когда я вызываю функцию (из консоли AWS или CLI), я могу видеть сообщения в журналах, но обратный вызов для getItem() никогда не вызывается.

Я попытался с выполнением getItem (params) без обратного вызова, а затем определил обратные вызовы для полного, успешного и неудачного, но когда я делаю send(), даже полный обратный вызов также не вызывается.

Я знаю, что вызовы асинхронны, и я подумал, что, возможно, лямбда-функция заканчивалась до того, как запрос был выполнен, и поэтому обратный вызов не будет вызываться, но я добавил простой глупый цикл в конце функции и вызов завершается через 3 секунды без вызова обратных вызовов.

Я пробовал с различными функциями batchGetItem, getItem, listTables и scan. Результат одинаков, нет ошибки, но функция обратного вызова никогда не вызывается.

Я уверен, что если я запрошу dynamoDB без использования Lambda, это даст мне результаты, поэтому мне действительно интересно, почему здесь ничего не происходит.

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

Политика выглядит так:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": "arn:aws:lambda:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:GetItem",
                "dynamodb:BatchGetItem",
                "dynamodb:Scan",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:GetRecords",
                "dynamodb:ListTables"
            ],
            "Resource": "arn:aws:dynamodb:*:*:*"
        },
        {
            "Action": [
                "logs:*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

Я запустил политику в симуляторе, и это сработало, как я думал. Предложения?

Ответы

Ответ 1

Итак, оказывается, что код правильный. Проблема заключается в том, что API-интерфейс dynamodb использует все эти обратные вызовы и в основном функция заканчивается до того, как данные были восстановлены.

Самое быстрое исправление - удалить вызов context.succeed(), и данные будут восстановлены. Конечно, использование асинхронного модуля помогло бы, и если вы не захотите это использовать, просто добавьте счетчик или логическое значение в ваш обратный вызов, а затем подождите, пока значение не изменится, что указывает на то, что вызван обратный вызов (какой отстой если вы думаете об этом)

Ответ 2

У меня были некоторые подобные проблемы, и я не нашел много полезных ресурсов. Вот что я в итоге сделал. Возможно, кто-то умнее скажет нам, если это самое лучшее.

function getHighScores(callback) {
    var params = {
        TableName : 'sessions',
        ScanFilter: {"score":{"AttributeValueList":[{"N":"0"}], "ComparisonOperator":"GT"}},
    };
    var dynamo = new AWS.DynamoDB();
    dynamo.scan(params, function(err, data) {
        if (err) {
            console.log (err)
            callback(err);
        } else {
            callback(data.Items);
            console.log(data.Items);
        }
    });
} 



getHighScores(function (data) {
    console.log(data);
    context.succeed(data);
});

Таким образом, передача обратного вызова через основную функцию в меньшую функцию позволяет приложению продолжать работу до завершения Динамо. Сохраняйте context.success в вторичной функции или продолжать другие функции там.

Ответ 3

Моя проблема в том, что моя лямбда работала в VPC, чтобы подключиться к ElastiCache. Это вызывает любые запросы к общедоступным интернет-ресурсам, таким как DynamoDB и Gateway API, чтобы вешать бесконечно. Я должен был настроить NAT-шлюз в своем VPC для доступа к DynamoDB.

Ответ 4

Чтобы избежать аддонов обратного вызова, используйте Promises. На youtube есть несколько хороших обучающих программ, которые называют funfunfunction.