Не работает функция лямбда-узла AWS - PullRequest
0 голосов
/ 04 июня 2018

У меня есть функция AWS Lambda, обслуживаемая через шлюз API AWS.Кажется, все работает нормально по большей части.Есть одна функция нашего API, которая работает неправильно.Это веб-крючок, который получает входящие факсы и электронные письма, чтобы мы знали, что они пришли.

Мы проверили все, и это прекрасно работает на нашей локальной машине и даже на провайдерах, таких как линодеили цифровой океан.Наша проблема заключается только в том, что при развертывании с AWS Lambda.

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

В журналах облачного наблюдения за лямбдой отображается console.log(req.body.MediaUrl);, но на stdout или stderr нет других выходных данных.Даже если я добавлю очевидные недостатки, ошибок не будет.Это почти так, как будто функция молча терпит неудачу без объяснения причин.

Я смог заставить его работать, если я отправил 2-3 почтовых запроса в течение 1-2 секунд после другого.1, может быть, 2 письма будут отправлены, но не все из них.Если один почтовый запрос отправляется в обычном режиме, вы никогда не получите письмо.

// Define a handler for when the fax is initially sent
const nodemailer = require('nodemailer');
const aws = require('aws-sdk');

// Start Email Logic
// AWS access keys are built into Lambda, modify permissions of the executor role
aws.config.update({region: 'us-west-2'});

let transporter = nodemailer.createTransport({
  SES: new aws.SES({
    apiVersion: '2010-12-01',
  }),
 });

exports.received = function(req, res) {

  transporter.sendMail({
  from: '"Fax" <fax@domain.com>',
  to: process.env.FAX_ADDRESS,
  subject: 'A new fax from ' + req.body.From,
  text: 'You can view the fax at this url:\n\n' + req.body.MediaUrl,
}, (err, info) => {
  if (err) {
    console.log(err);
  } else {
    console.log(info.envelope);
    console.log(info.messageId);
    console.log('Email Sent');
  }
});

// log the URL of the PDF received in the fax just in case email fails
console.log(req.body.MediaUrl);

  res.status(200);
  res.send();
};

Кстати, в приведенном выше коде есть еще один файл со всеми необходимыми экспресс-пунктами для правильного обслуживания.Опять же, он отлично работает на локальных, других серверах и даже иногда при затоплении лямбды;хотя он никогда не работает последовательно на Lambda.

Я думаю, либо я идиот, которому нужно спать, либо я что-то упускаю из-за Lambda.Может кто-нибудь пролить свет на то, что мне не хватает?

РЕДАКТИРОВАТЬ:

Благодаря Майклу и Хен все стало на свои места.При работе с Lambda лямбда-функция отключается в тот момент, когда она проходит через основную логику процесса.Он не будет ждать завершения ожидающих асинхронных элементов.Следующее изменение устранило мою проблему при использовании Express с Lambda.

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

exports.received = function(req, res) {

  // log the URL of the PDF received in the fax just in case email fails
  console.log(req.body.MediaUrl);

  transporter.sendMail({
  from: '"Fax" <fax@domain.com>',
  to: process.env.FAX_ADDRESS,
  subject: 'A new fax from ' + req.body.From,
  text: 'You can view the fax at this url:\n\n' + req.body.MediaUrl,
}, (err, info) => {
  if (err) {
    console.log(err);
    res.status(500);
    res.send();
  } else {
    console.log(info.envelope);
    console.log(info.messageId);
    console.log('Email Sent');
    res.status(200);
    res.send();
  }
});
};

Ответы [ 3 ]

0 голосов
/ 04 июня 2018

Это не означает, что ничего не происходит, это просто приостановка анимации.Попытка повторить это в короткой последовательности фактически позволяет более ранним попыткам иметь достаточно времени выполнения для завершения.

Проблема, кажется, здесь:

res.status(200);
res.send();

Они должны быть внутри обратного вызова от sendMail().Вы не должны возвращать успех до тех пор, пока не достигнете успеха, но вы возвращаете его до этого, поскольку sendMail() является асинхронным.

Вы не можете ожидать, что Lambda продолжит делать что-то для вас после того, как вы это сказаливсе готовоЛямбда - это запрос / ответ. Запустите функцию, сделайте что-нибудь, верните ответ, остановите.Процесс заморожен, и биллинг во время выполнения останавливается.Если в цикле событий все еще есть вещи, то они просто зависают, в зависимости от значения context.callbackWaitsForEmptyEventLoop, которое, я сомневаюсь, должно / могло быть безопасно изменено с помощью express.

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

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

Если вы продублируете строку console.log(req.body.MediaUrl); как внутри обратного вызова, так и оставите ее там, где она есть сейчас, при условии, что значение отличается для каждого запроса, вы должны собрать некоторые доказательства, чтобы подтвердить то, что я утверждаю, здесь.


¹ Лямбда - это запрос / ответ .Сами лямбда-функции также могут вызываться асинхронно как вызовы «события», так что «ответ» внешнему вызывающему абоненту является лишь свидетельством того, что инфраструктура Lambda согласилась выполнить функцию для вас, в случаях, когда вы не хотите илинужно дождаться фактического ответа, но это не актуально в этом контексте.Лямбда-функции все еще являются запросом / ответом, даже при том, что в этой альтернативной модели ответ от функции отбрасывается, и вызов повторяется дважды, если выбрасывается исключение.

0 голосов
/ 02 апреля 2019

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

0 голосов
/ 04 июня 2018

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

То, что вы испытали, - это прекращение лямбды до завершения SendMail. Отправка одного электронного письма, если вы отправляете пару запросов вместе, - всего лишь игра времени.

Я предлагаю вамиспользовать *await transporter.sendMail*, а также иметь возможность сообщать о реальном успехе / неудаче вместо того, чтобы всегда возвращать 200.

...