Лямбда-функция AWS приводит к таймауту, когда присутствует вызов базы данных - PullRequest
0 голосов
/ 17 мая 2019

У меня есть API-шлюз с некоторыми функциями AWS Lambda, которые выполняют вызов базы данных (используя sequelize.js) и возвращают результат в виде объекта JSON.

Когда я запускаю код локально, я получаю результаты,но при развертывании кода любой метод, в котором есть вызов базы данных, приводит к внутренней ошибке сервера.

Следующий код возвращает сообщение:

module.exports.testFunction = (event, context, callback) => {
    return callback(null, {
        statusCode: 200,
        body: JSON.stringify({
            message: 'Test function is working.'
        })
    });
};

Следующий код регистрируетбаза данных приводит к появлению CloudWatch, но через 6 секунд тайм-аут вызова API, а затем возвращается внутренняя ошибка сервера (502):

module.exports.getAll = (event, context, callback) => {
    Entity.findAll().then(result => {
        console.log(JSON.stringify(result));
        return callback(null, {
            statusCode: 200,
            body: JSON.stringify(result)
        });
    });
};

Какие-нибудь решения, чтобы заставить возврат работать?

Ответы [ 3 ]

3 голосов
/ 17 мая 2019

Прежде всего поздравляю, что вы смогли успешно определить проблему. Однако есть много понятий, которые можно извлечь из возникшей проблемы. Давайте обсудим некоторые из них.

Лямбда, холодный старт, выпуск

Чтобы понять концепцию холодного старта в лямбде, неизбежно идти дальше, не понимая, как работает AWS Lambda. Пожалуйста, обратитесь к указанной ниже ссылке, которая объясняет общую работу лямбды в разделе AWS re: Invent 2018

AWS Lambda под капотом (Video Link): https://www.youtube.com/watch?v=QdzV04T_kec

Возвращаясь к вопросу холодного запуска, поскольку наши лямбда-функции выполняются в контейнере, после выполнения контейнер уничтожается, если в течение ~ 15 минут бездействия не будет никаких дальнейших вызовов функций. После того, как контейнер убит, любой будущий вызов для выполнения той же функции потребует установки нового контейнера, который может занять> 5 секунд (наиболее вероятная причина, по которой ваш вызов API прерывается через 6 секунд). Тем не менее, есть много доступных вариантов, которые могут сохранить вашу лямбду теплой. Пожалуйста, обратитесь по указанной ниже ссылке от сообщества Serverless.

Сохранение функций лямбды в тепле (ссылка на блог): https://serverless.com/blog/keep-your-lambdas-warm/

Увеличение времени ожидания лямбды

«Мне пришлось войти в консоль AWS и увеличить время ожидания до 20 секунд».


Хотя этот подход полностью приемлем, но, поскольку вы используете безсерверную технологию (явный файл serverless.yml), вы можете напрямую изменить период ожидания лямбда по умолчанию (который составляет 6 секунд). Пожалуйста, обратитесь к приведенному ниже фрагменту кода и ссылке для дальнейшего понимания.

provider:
 name: was
 runtime: nodejs6.10
 memorySize: 512 # optional, in MB, default is 1024
 timeout: 10 # optional, in seconds, default is 6

Руководство по использованию безсервисной лямбда-функции AWS (ссылка на блог): https://serverless.com/framework/docs/providers/aws/guide/functions/

1 голос
/ 17 мая 2019

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

0 голосов
/ 20 мая 2019

Добавив еще один ответ, я обнаружил, в чем была проблема.

Установка таймаута в 20 заставила его работать, но каждый звонок занимал около 10 секунд, а не только холодный старт. Однако результаты запроса были получены уже через несколько миллисекунд.

Очевидно, что AWS Lambda передает аргумент контекста в функциях-обработчиках , и одним из его свойств является callbackWaitsForEmptyEventLoop, который по умолчанию имеет значение true:

callbackWaitsForEmptyEventLoop - Установите в false, чтобы сразу отправлять ответ при выполнении обратного вызова, вместо того, чтобы ждать, пока цикл событий Node.js будет пустым. Если false, любые ожидающие события будут продолжать выполняться во время следующего вызова.

Я установил для свойства значение false в начале функции, и теперь каждый вызов занимает всего ~ 70 мс.

module.exports.getAll = (event, context, callback) => {
    context.callbackWaitsForEmptyEventLoop = false;
    Entity.findAll().then(result => {
        console.log(JSON.stringify(result));
        return callback(null, {
            statusCode: 200,
            body: JSON.stringify(result)
        });
    });
};
...