Как вызвать DynamoDB из итератора в асинхронном лямбда-обработчике - PullRequest
0 голосов
/ 07 января 2019

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

Код для функции Lambda выглядит следующим образом:

const AWS = require('aws-sdk');
AWS
    .config
    .update({accessKeyId: process.env.AWS_KEY, secretAccessKey: process.env.AWS_SECRET});

AWS
    .config
    .update({region: "us-west-1"});

exports.handler = async(event) => {
    ///some other stuff to set up the variables below
    event
        .Records
        .forEach((record) => {

            var docClient = new AWS
                .DynamoDB
                .DocumentClient({convertEmptyValues: true, endpoint: "dynamodb.us-west-1.amazonaws.com"});

            var db_params = {
                TableName: entity,
                Key: entityKey,
                "UpdateExpression": update_expression,
                "ExpressionAttributeNames": expression_attribute_names,
                "ExpressionAttributeValues": expression_attribute_values,
                "ReturnValues": "ALL_NEW"
            };

            console.log('executing updateObjectPromise');
            docClient
                .update(db_params)
                .promise()
                .then((item) => {
                    console.log(entity + " inserted");
                    console.log(item);
                    return item;
                })
                .catch((error) => {
                    console.log("ERROR: ");
                    console.log(error);
                    return error;
                });

            console.log("end of function");
        });
};

Этот код повторяется, но обещание обновления никогда не запускается и не завершается. await не работает, потому что итератор не асинхронный. Я попытался использовать пакет async npm и асинхронный итератор, но даже при использовании await вызов update дает то же самое поведение. Похоже, что бы я ни делал, вызов либо никогда не запускается, либо не завершается до завершения функции. Я не нашел примеров, чтобы кто-нибудь делал что-то подобное. Кто-нибудь может помочь?

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Функция обратного вызова forEach - это функция синхронизации, если вы хотите использовать синтаксис async/await для массива, вы должны знать, как работает async/await.

Вы возвращаете item в .then объеме ???? (Я думаю, вы хотите вернуть элемент для лямбда-функции). Если вы не используете ключевое слово await или не возвращаете что-либо для лямбда-функции async, это может привести к ошибке тайм-аута.

Быстрое решение для вашего случая: просто используйте old school for loop (у нас есть способ решить эту проблему)

exports.handler = async (event) => {
  ///some other stuff to set up the variables below
  let results = [];
  var docClient = new AWS
    .DynamoDB
    .DocumentClient({ convertEmptyValues: true, endpoint: "dynamodb.us-west-1.amazonaws.com" });
  try {
    for (let i = 0; i < event.Records.length; i++) {
      var db_params = {
        TableName: entity,
        Key: entityKey,
        "UpdateExpression": update_expression,
        "ExpressionAttributeNames": expression_attribute_names,
        "ExpressionAttributeValues": expression_attribute_values,
        "ReturnValues": "ALL_NEW"
      };
      console.log('executing updateObjectPromise');
      let item = await docClient
        .update(db_params)
        .promise();
      console.log(entity + " inserted");
      console.log(item);
      results.push(item);
    }
  } catch (error) {
    console.log("ERROR: ");
    console.log(error);
    throw error;
  }
  return results; // return and finish lambda function
};
0 голосов
/ 07 января 2019
const AWS = require('aws-sdk')

AWS
    .config
    .update({ accessKeyId: process.env.AWS_KEY, secretAccessKey: process.env.AWS_SECRET })

AWS
    .config
    .update({ region: 'us-west-1' })

// Initialize this only once.
const docClient = new AWS
    .DynamoDB
    .DocumentClient({ convertEmptyValues: true, endpoint: 'dynamodb.us-west-1.amazonaws.com' })

exports.handler = async (event) => {
    ///some other stuff to set up the variables below

    const promises = event.Records.map(record => {
        const db_params = {
            TableName: entity,
            Key: entityKey,
            'UpdateExpression': update_expression,
            'ExpressionAttributeNames': expression_attribute_names,
            'ExpressionAttributeValues': expression_attribute_values,
            'ReturnValues': 'ALL_NEW',
        }

        return docClient
            .update(db_params)
            .promise()
            .then((item) => {
                console.log(entity + ' inserted')
                console.log(item)
                return item
            })
            .catch((error) => {
                console.log('ERROR: ')
                console.log(error)
                return error
            })
    })

    return Promise.all(promises)
}
...