Как функция AWS Lambda может обновить все записи в таблице DynamoDB?

Я работаю над функцией AWS Lambda (Node 4.3), которой необходимо просмотреть все элементы в таблице DynamoDB и обновить определенные атрибуты.

Проблема, с которой я сталкиваюсь, заключается в том, как заставить Lambda ждать завершения всех операций DynamoDB.

var async = require('async');
var aws = require('aws-sdk');
var doc = new aws.DynamoDB.DocumentClient();

exports.handler = (event, context, callback) => {
    doc.scan({
        TableName: 'Occupations_dev'
    }, function (err, data) {
        console.log(data.Items.length);

        var funcs = [];

        data.Items.forEach(function (item) {
            funcs.push(function (cb) {
                item.Popularity = 0;

                doc.put({
                    TableName: 'Occupations_dev',
                    Item: item
                }, function (err, data) {
                    if (err) {
                        console.log("ERROR: " + item.Name);
                        cb(err);
                    } else {
                        console.log('Finished put for ' + item.Id)
                        cb(null, item);
                    }
                });
            });
        });

        async.parallel(funcs, function (err, results) {
            console.log('Finished');

            if (err) {
                context.fail(err);
            } else {
                callback(null, 'Finished');
            }
        });
    });
};

Я попытался использовать async.parallel, чтобы дождаться завершения всех запросов db.put, но это заканчивается ошибкой Process exited before completing request всякий раз, когда запускается функция Lambda.

Он обновляет некоторые элементы DynamoDB, но точно не все.

Я добавил несколько вызовов console.log, когда есть ошибки, но единственный вывод, который я вижу в журнале, это:

START RequestId: b72fd7c6-14ed-11e7-a95a-c1185af4e870 Version: $LATEST
2017-03-30T02:08:11.691Z    b72fd7c6-14ed-11e7-a95a-c1185af4e870    1362
END RequestId: b72fd7c6-14ed-11e7-a95a-c1185af4e870
REPORT RequestId: b72fd7c6-14ed-11e7-a95a-c1185af4e870  Duration: 37165.80 ms   Billed Duration: 37200 ms   Memory Size: 128 MB Max Memory Used: 128 MB 
RequestId: b72fd7c6-14ed-11e7-a95a-c1185af4e870 Process exited before completing request

Как правильно заставить функцию Lambda ждать, пока все не будет сделано? (Это небольшой объем данных, поэтому я не беспокоюсь о том, что работа будет длиться более 5 минут и истечет время ожидания.)


person Mark Biek    schedule 30.03.2017    source источник
comment
Я предполагаю, что Process exited before completing request означает, что в вашем коде js есть какая-то другая ошибка - работает ли это локально и только ошибка на AWS Lambda?   -  person Bobby Matson    schedule 30.03.2017
comment
Я относительно новичок в Lambda, поэтому я не знаю, как запустить его локально. Есть ли способ получить больше информации об ошибках от Lambda? Я ничего не вижу в журналах CloudWatch.   -  person Mark Biek    schedule 30.03.2017
comment
Странно, я считаю, что они должны быть в Cloudwatch. Когда вы запускаете фрагмент кода, видите ли вы какие-либо операторы console.log? Они должны пройти через вывод журнала в Lambda.   -  person Bobby Matson    schedule 30.03.2017
comment
Я добавил некоторые операторы console.log для случаев, когда doc.put имеет ошибку, но я не вижу ни одного из них в журнале. Я вижу только вывод console.log(data.Items.length); и около 60 операторов Finished put for..., прежде чем он умрет.   -  person Mark Biek    schedule 30.03.2017
comment
Дикий! Есть ли в DynamoDB какие-либо ограничения на одновременные подключения? Если вы пытаетесь вставить слишком много записей асинхронно, это может привести к ошибке. Возможно, попробуйте использовать синхронный подход, такой как async.series или Promise.all, и посмотрите, будет ли ваш результат таким же.   -  person Bobby Matson    schedule 30.03.2017
comment
Это интересная мысль. Я попробую async.auto (или, может быть, waterfall) и посмотрю, что получится. Спасибо за помощь!   -  person Mark Biek    schedule 30.03.2017
comment
Без проблем! Я отредактировал свой последний комментарий, я думаю, что async.series это то, что вы хотели бы попробовать. Дайте мне знать, как это происходит!   -  person Bobby Matson    schedule 30.03.2017
comment
@BobbyMatson async.series сделал свое дело! Похоже, вы были правы насчет того, что я завалил DynamoDB слишком большим количеством подключений. Вы должны опубликовать это как ответ, чтобы я мог принять его и отдать вам должное. Спасибо еще раз. Я потратил буквально весь день, пытаясь понять это.   -  person Mark Biek    schedule 30.03.2017
comment
Сделаю! Рад, что это сработало   -  person Bobby Matson    schedule 30.03.2017


Ответы (2)


Вызовы функций async.parallel происходят асинхронно, что, вероятно, переполняет DynamoDB множеством одновременных обновлений и вызывает ошибки «слишком много подключений» на уровне БД.

Я бы рекомендовал использовать синхронную операцию, например async.series, для выполнения обновлений БД. У DynamoDB не должно возникнуть проблем с обработкой этих обновлений одно за другим.

person Bobby Matson    schedule 30.03.2017

Сообщение «Процесс завершен до завершения запроса» означает, что функция Javascript завершилась до вызова context.done (или context.succeed и т. д.).

Вот несколько предложений:

Прежде всего, попробуйте увеличить лимит памяти для функции. Эта строка Memory Size: 128 MB Max Memory Used: 128 MB может указывать на то, что памяти не хватает и процесс просто убивается без вызова последнего обратного вызова.

То, что вы, вероятно, увидите после увеличения лимита памяти, будет одним из следующих:

  • Ваша функция истечет время ожидания. В этом случае вам может потребоваться увеличить выделенную емкость таблицы (и/или тайм-аут вашего лямбда)

  • Даже если функция завершится без тайм-аута, вы, вероятно, увидите, что не все записи таблицы обработаны. Это связано с тем, что операции сканирования и запроса могут возвращать не все строки таблицы, если общее количество отсканированных элементов превышает максимальный размер набора данных, равный 1 МБ. Когда сканирование завершится, вы должны проверить, возвращается ли LastEvaluatedKey вместе с данными. Если это так, вы должны выполнить еще одно сканирование, указав значение LastEvaluatedKey в качестве параметра ExclusiveStartKey.

person xtx    schedule 30.03.2017