【问题标题】:Unhandled promise rejection on AWS lambda with async / await使用 async / await 在 AWS lambda 上未处理的承诺拒绝
【发布时间】:2018-09-28 09:27:22
【问题描述】:

最近,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 函数之外?任何帮助将不胜感激。

【问题讨论】:

  • 我遇到了同样的问题。 Node 8.10 运行时的 AWS 博客仅返回 Promises,请参阅 amzn.to/2J1Y49r,但他们没有讨论如何处理拒绝。真的很奇怪。或许可以在 AWS 官方论坛上提问?
  • 刚刚在AWS官方论坛上发了一个关于这个话题的问题:amzn.to/2JpoHEY
  • 我的最小测试按预期工作exports.handler = async (event) =&gt; { throw Error('rejected') };。 lambda 因我的拒绝错误而失败。这可能是一个山姆错误
  • 嗯,您的最小测试仍然会导致未处理的承诺拒绝。
  • @MartinDonath 您确定您使用的是 nodejs 8.10 运行时吗? SAM 中的错误是本地的吗?

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


【解决方案1】:

任何时候你在 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;
};

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

【讨论】:

  • 虽然确实在那个例子中他们确实返回了错误,但这似乎不是一个解决方案。通过只返回错误,您隐藏了它是一个错误的事实,并且必须求助于您自己的错误处理解决方案来区分常规返回值和错误返回值,而不是语言机制。无论哪种方式,在我在原始帖子以及我的第二个示例中发布的link 中,都会引发错误而不会导致警告。所以这似乎有可能,我只是不确定如何......
  • 文档清楚地表明:1.调用此 Lambda 函数时,它将通知 AWS Lambda 函数执行完成但出现错误并将错误信息传递给 AWS Lambda。如果您使用 Node.js 运行时版本 8.10.2 的异步功能编写函数,您将获得相同的结果。自定义错误处理使创建无服务器应用程序变得更加容易。此功能集成了 Lambda 编程模型 [...] 支持的所有语言。我认为他们必须更新 AWS Lambda 以支持 nodejs async/await 错误处理功能。
【解决方案2】:

AWS 似乎已经解决了这个问题。使用 Node 8.10 运行时使用以下函数进行测试,我不再看到任何未处理的拒绝:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 我个人希望他们将其处理为 catch 语句,他们将附加到导出的异步函数。
    猜你喜欢
    • 2018-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-10
    • 2018-09-16
    • 2020-12-24
    • 1970-01-01
    相关资源
    最近更新 更多