使用async / await对AWS lambda进行未处理的承诺拒绝

时间:2018-04-18 08:17:16

标签: node.js async-await aws-lambda

最近AWS宣布了其lambda函数(Node.js 8.10 runtime available)的nodejs8.10运行时的可用性。虽然这对于快乐的流程来说似乎很好,但是我遇到了一些不愉快的流程问题,即我得到了“UnhandledPromiseRejectionWarnings”。

我正在使用以下代码。我的想法是,我提供了一个不存在的对象的密钥来测试该场景的不满意流程。我的目标是将错误记录并传播出lambda,因为我在这里没有理智的处理方式(我无法在这个lambda函数中检索新密钥)。我也希望能够在调用者中使用错误(例如,另一个lambda函数或步骤函数)。

'use strict';

const AWS = require('aws-sdk');

exports.handler = async (event) => {
  let data;
  try {
    data = await getObject(event.key);
  } catch (err) {
    console.error('So this happened:', err);
    throw err;
  }

  return data;
}

const getObject = async (key) => {
  let params = {
    Bucket: process.env.BUCKET,
    Key: key
  };

  const s3 = new AWS.S3();

  let data;
  try {
    data = await s3.getObject(params).promise();
  } catch(err) {
    console.log('Error retrieving object');
    throw err;
  }

  console.log('Retrieved data');
  return data.Body.toString('utf8');
}

如果我运行这个lambda函数(使用SAM local),我会像我想的那样从lambda中得到错误,但我也收到以下警告:

2018-04-18T07:54:16.217Z    6ecc84eb-46f6-1b08-23fb-46de7c5ba6eb    (node:1) UnhandledPromiseRejectionWarning: NoSuchKey: The specified key does not exist.
    at Request.extractError (/var/task/node_modules/aws-sdk/lib/services/s3.js:577:35)
    at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
    at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
    at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:683:14)
    at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:685:12)
    at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
2018-04-18T07:54:16.218Z    6ecc84eb-46f6-1b08-23fb-46de7c5ba6eb    (node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
2018-04-18T07:54:16.218Z    6ecc84eb-46f6-1b08-23fb-46de7c5ba6eb    (node:1) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

我不确定如何处理这个问题,同时仍然将错误传播出lambda函数(根据lambda function errors (node.js)应该是一个有效的场景)

我也尝试过运行类似(对我而言)的场景,如下面的那样(尝试查明并理解错误),但不知怎的,我在这里得不到警告,它按预期工作(错误返回来自lambda函数)。

'use strict';

const AWS = require('aws-sdk');

exports.handler = async (event) => {
  let data;
  try {
    data = await directBoom();
  } catch (err) {
    console.error('So this happened:', err);
    throw err;
  }

  return data;
}

const directBoom = async () => {
  let data;
  try {
    data = await Promise.reject(new Error('boom!')); 
  } catch(err) {
    throw err;
  }

  return data;
}

我在这里缺少什么,为什么两个例子表现不同?如何在第一个示例中摆脱警告,同时仍然能够将错误传播出lambda函数?任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:5)

任何时候在promise / async函数中抛出或拒绝并且不使用catch处理它,Node将返回该警告。

AWS上的example不会在catch块中抛出错误,而是返回它:

let AWS = require('aws-sdk');
let lambda = new AWS.Lambda();
let data;

exports.handler = async (event) => {
    try {
        data = await lambda.getAccountSettings().promise();
    }
    catch (err) {
        console.log(err);
        return err;
    }
    return data;
};

在具有大量异步函数的大型应用程序中,如果单个未处理的承诺终止,那么节点进程就会很糟糕。这可能不适用于简单的Lambda函数,其中抛出终止进程的错误是期望的行为。但是,如果您不希望Node警告您,请返回错误。

答案 1 :(得分:2)

AWS似乎已解决此问题。使用Node 8.10运行时使用以下功能进行测试,我再也看不到任何未处理的拒绝:

exports.handler = async (event) => { 
  throw new Error("broken")
};

答案 2 :(得分:0)

我通过使用上下文对象中的fail方法来通知Lambda函数执行失败,来对此进行管理。

'use strict'

exports.handler = async function (event, context) {
  try {
    throw new Error('Something went wrong')
  } catch (err) {
    context.fail(err)
  }
}