Ответ довольно прост, если вам нужен ответ. Но что, если вы не хотите ждать ответа?


HTTP без ожидания


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


Так как же нам это сделать в NodeJS?


Давайте сначала рассмотрим наивный пример запроса (без обработки ошибок), где мы ждем ответа.


Только для этого примера мы создадим асинхронную функцию узла «запрос», которая возвращает обещание, которое мы можем ждать.


```javascript


константа https = требуется ('https')


постоянный URL = требуется('url')


запрос асинхронной функции (url, данные) {


вернуть новое обещание ((разрешить, отклонить) => {


пусть req = https.request(URL.parse(url), function (res) {


пусть тело = ''


res.on('данные', (фрагмент) => {тело += фрагмент})


res.on('конец', () => { разрешение(тело) })


требуется запись (данные)


запрос.конец()


Тогда наша лямбда будет выглядеть так:


```javascript


exports.handler = асинхронный (событие, контекст) {


let result = await request('https://metric-service.com', metrics)


вернуть результат


Чтобы вызвать наш HTTP-запрос внутри Lambda, мы используем «ожидание», которое выдает запрос, а затем ожидает ответа.


Если службе агрегатора метрик требуется 950 миллисекунд для обработки запроса и возврата кода состояния, нам будет выставляться счет за дополнительную секунду при каждом вызове.


В течение этого времени ожидания наша функция Lambda неактивна, но AWS по-прежнему выставляет нам счет за это время. При использовании AWS Lambda вы платите за прошедшее время, а не за использованное процессорное время.


Хотя Lambda необычайно дешев, с большими объемами транзакций, эти короткие ожидания в 950 миллисекунд могут составить значительный счет.


Не ждите


Итак, что произойдет, если мы просто не вызовем «ожидание» и, следовательно, не будем ждать ответа на наш HTTP-запрос?


```javascript


exports.handler = асинхронный (событие, контекст) {


/ подождите / request('https://example.com', метрики)


вернуть «готово»


:::Информация


Странные вещи случаются


Иногда запрос отправляется, а иногда запрос не отправляется.


Иногда запрос поступает агрегатору метрик сразу, а иногда запрос поступает после следующего запуска нашей лямбды. Что происходит?


Замораживание контейнеров Lambda


Функции Lambda выполняются внутри контейнера AWS Firecracker. Когда вы возвращаетесь из функции Lambda, AWS немедленно замораживает контейнер и его глобальное состояние. При следующем вызове Lambda контейнер разморозится для обслуживания нового вызова.


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


Как решить?


Мы могли бы попробовать короткий сон, чтобы дать время для отправки запроса? Но как долго мы должны ждать.


```javascript


exports.handler = асинхронный (событие, контекст) {


/ подождите / request('https://example.com', метрики)


жду сна(100)


вернуть «готово»


Это вряд ли кажется надежным.


Ожидание передачи запроса


Правильное решение — использовать Node req.end(,,callback) API и дождаться полной отправки запроса, но не ждать получения ответа.


Вот пример:


```javascript


константа https = требуется ('https')


постоянный URL = требуется('url')


запрос асинхронной функции (url, данные) {


вернуть новое обещание ((разрешить, отклонить) => {


пусть запрос = https.request(URL.parse(url))


требуется запись (данные)


req.end(null, null, () => {


/ Запрос полностью отправлен /


разрешить (требуется)


Обратите внимание, что запрос разрешается с помощью обратного вызова end на объекте «req», а не на объекте «res» в предыдущем примере.


Эта модифицированная функция запроса должна вызываться нашей лямбдой с помощью «ожидания». В этом случае мы ждем не ответа HTTP, а полной отправки запроса. Это намного быстрее, чем 750 миллисекунд для получения ответа с нашими показателями, обычно менее 20 миллисекунд.


```javascript


exports.handler = асинхронный (событие, контекст) {


ожидание запроса('https://example.com', метрики)


вернуть «готово»


Альтернативные шаблоны проектирования


Есть много других отличных способов избежать ожидания и блокировки в функциях Lambda, таких как использование функций Step, очередей SQS и прямой вызов функций Lambda как событий без ожидания. Подумайте о наилучшем подходе для вашего приложения, но если вы должны использовать HTTP и вам не нужно ждать ответа, рассмотрите описанный выше метод, чтобы сократить время ожидания и счет за AWS.


SenseDeep


Наша SenseDeep Serverless Developer Studio использует этот метод в Watcher Lambda, который отслеживает ваши Lambda, запускает сигналы тревоги и получает данные журнала. Нам нужно, чтобы Наблюдатель был исключительно быстрым и не ждал никаких запросов REST/HTTP API. Таким образом, Наблюдатель использует этот метод без ожидания при отправке статуса обратно в сервис SenseDeep.


SenseDeep Troubleshooting


Чтобы узнать больше о SenseDeep Serverless Developer Studio и попробовать ее бесплатно, перейдите по ссылке: https://www.sensedeep.com.


Использованная литература


Вот еще несколько полезных материалов об асинхронном программировании Lambda и AWS.