13

我在 AWS 上并在 Node.js 中使用 AWS SDK for JavaScript。我正在尝试构建一个 AWS Lambda 函数,在里面我想获取我所有的 Amazon EC2 实例的列表,但我似乎无法让它工作。谁能发现我做错了什么?

这是我的 Lambda 函数代码:

var AWS = require('aws-sdk');
AWS.config.region = 'us-west-1';

exports.handler = function(event, context) {
    console.log("\n\nLoading handler\n\n");
    var ec2 = new AWS.EC2();
    ec2.describeInstances( function(err, data) {
        console.log("\nIn describe instances:\n");
      if (err) console.log(err, err.stack); // an error occurred
      else     console.log("\n\n" + data + "\n\n"); // successful response
    });
    context.done(null, 'Function Finished!');  
};

这是我的政策(我认为这是正确的?)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:*"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
    "Effect": "Allow",
    "Action": [
      "ec2:*"
    ],
    "Resource": "arn:aws:ec2:*"
  },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}

如果我在'ec2'上执行console.log,我会得到:

{ config: 
   { credentials: 
      { expired: false,
        expireTime: null,
        accessKeyId: 'XXXXXXXXXXXXXXXXXX',
        sessionToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
        envPrefix: 'AWS' },
     credentialProvider: { providers: [Object] },
     region: 'us-west-1',
     logger: null,
     apiVersions: {},
     apiVersion: null,
     endpoint: 'ec2.us-west-1.amazonaws.com',
     httpOptions: { timeout: 120000 },
     maxRetries: undefined,
     maxRedirects: 10,
     paramValidation: true,
     sslEnabled: true,
     s3ForcePathStyle: false,
     s3BucketEndpoint: false,
     computeChecksums: true,
     convertResponseTypes: true,
     dynamoDbCrc32: true,
     systemClockOffset: 0,
     signatureVersion: 'v4' },
  isGlobalEndpoint: false,
  endpoint: 
   { protocol: 'https:',
     host: 'ec2.us-west-1.amazonaws.com',
     port: 443,
     hostname: 'ec2.us-west-1.amazonaws.com',
     pathname: '/',
     path: '/',
     href: 'https://ec2.us-west-1.amazonaws.com/' } }
4

2 回答 2

13

最可能的原因是您在 Lambda 函数完成对 EC2 DescribeInstances API 的调用之前明确终止了它。

原因是 Lambda 假定您的代码在您调用context.done(...). 这发生在通话之前console.log(... data ...)

之所以会出现这种奇怪的排序,是因为 NodeJS 的工作方式以及 AWS SDK for JavaScript 的工作方式。在 NodeJS 中,你永远不应该阻止执行。对 Web 服务(例如 EC2)的调用会阻止执行。因此,适用于 JavaScript 的 AWS 开发工具包(以及大多数 NodeJS 库)通过异步调用来工作。

大多数情况下,当您进行异步调用时,您会将回调函数传递给该调用。当结果准备好后,NodeJS 会执行回调函数。

在您的代码中,这function(err, data) {...}就是回调函数。这不会立即执行,而是会在 NodeJS 看到ec2.describeInstances调用已收到其结果时安排执行。

一旦你安排了回调的执行,你就在打电话context.done(...),它告诉 Lambda:我已经完成了,你可以杀了我。在 EC2 DescribeInstances 调用接收其数据并将其传递给您的回调函数之前,它很乐意服从并中断您的函数。

如何解决问题?

答案现在应该很清楚了:只需将context.done(...)调用移至回调函数内部,就在包含调用的 if/else 块之后console.log(...data...)

ec2.describeInstances( function(err, data) {
  console.log("\nIn describe instances:\n");
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log("\n\n" + data + "\n\n"); // successful response
  context.done(null, 'Function Finished!');  
});
于 2014-12-29T17:49:10.757 回答
1

截至 2019 年(10 月),给定的答案没有帮助,挖掘后我发现现在它是基于承诺的

exports.handler = async function(event) {
  const promise = new Promise(function(resolve, reject) {
      //your logic, goes here at the end just call resolve 
      resolve("data you want to return"); // here lamda exits 
    })
  return promise;// lamda does not  exits here, it waits for to resolve
}
于 2019-10-05T07:42:57.893 回答