【问题标题】:Data returned from promises with AWS-SDK for node and bluebird使用 AWS-SDK 为 node 和 bluebird 从 promise 返回的数据
【发布时间】:2015-08-15 17:13:09
【问题描述】:

我正在尝试为 AWS 中的每个区域获取所有注册的弹性 IP。我目前正在处理的代码如下:

logger.info('About to fetch Regions');
ec2.describeRegionsPromised({}).then(function (data) {
  var addressesPromises = [];

  logger.info('Fetched Regions');
  logger.info(data);

  _.forEach(data.Regions, function (region) {
    var ec2Addresses = _.create(ec2, {region: region.RegionName});

    addressesPromises.push(ec2Addresses.describeAddressesPromised());
  });

  logger.info('About to fetch addresses per region');

  return Promise.all(addressesPromises);
}).then(function (data) {
  logger.info('Fetched addresses per region');
  logger.debug(data);
}).catch(function (err) {
  logger.error('There was an error when fetching regions and addresses');
  logger.error(err);
});

这工作正常,但我的问题是我正在查看第二个.thenpromised-callback 函数data 参数,它的数据是一个数组,与第一个返回的区域长度相同请求

我知道我只在一个地区使用了 1 个弹性 IP。对于所有其他地区,我没有任何关联。

返回的 Regions 如下(实际上是格式化的 JSON):

Regions=[RegionName=eu-west-1, Endpoint=ec2.eu-west-1.amazonaws.com, RegionName=ap-southeast-1, Endpoint=ec2.ap-southeast-1.amazonaws.com, RegionName=ap-southeast-2, Endpoint=ec2.ap-southeast-2.amazonaws.com, RegionName=eu-central-1, Endpoint=ec2.eu-central-1.amazonaws.com, RegionName=ap-northeast-1, Endpoint=ec2.ap-northeast-1.amazonaws.com, RegionName=us-east-1, Endpoint=ec2.us-east-1.amazonaws.com, RegionName=sa-east-1, Endpoint=ec2.sa-east-1.amazonaws.com, RegionName=us-west-1, Endpoint=ec2.us-west-1.amazonaws.com, RegionName=us-west-2, Endpoint=ec2.us-west-2.amazonaws.com]

在 JSON 中应该是:

{ Regions: [] } //and so on

返回的弹性IP如下:

[ { Addresses: [ [PublicIp=XX.XX.XXX.XXX, AllocationId=eipalloc-XXXXXXXX, Domain=vpc] ] },
  { Addresses: [ [PublicIp=XX.XX.XXX.XXX, AllocationId=eipalloc-XXXXXXXX, Domain=vpc] ] },
  { Addresses: [ [PublicIp=XX.XX.XXX.XXX, AllocationId=eipalloc-XXXXXXXX, Domain=vpc] ] },
  { Addresses: [ [PublicIp=XX.XX.XXX.XXX, AllocationId=eipalloc-XXXXXXXX, Domain=vpc] ] },
  { Addresses: [ [PublicIp=XX.XX.XXX.XXX, AllocationId=eipalloc-XXXXXXXX, Domain=vpc] ] },
  { Addresses: [ [PublicIp=XX.XX.XXX.XXX, AllocationId=eipalloc-XXXXXXXX, Domain=vpc] ] },
  { Addresses: [ [PublicIp=XX.XX.XXX.XXX, AllocationId=eipalloc-XXXXXXXX, Domain=vpc] ] },
  { Addresses: [ [PublicIp=XX.XX.XXX.XXX, AllocationId=eipalloc-XXXXXXXX, Domain=vpc] ] },
  { Addresses: [ [PublicIp=XX.XX.XXX.XXX, AllocationId=eipalloc-XXXXXXXX, Domain=vpc] ] } ]

在响应中,我有一个对象数组,其中每个区域请求的对象键值都相同,这是错误的。

我希望在第二个响应中每个区域的值分辨率,将其余值设置为 null、未定义或类似。

总结一下。我不明白为什么解析一组 promise 的值(使用 .all)会在每个位置得到一组相同的值 - 这不是预期的结果。

这里发生了什么?提前致谢!

【问题讨论】:

  • Regions=[...] 表达式是什么?它既不是 JSON 也不是数组字面量。
  • 这是winston 执行.info() 的输出。把它想象成一个普通的 JSON,比如:{ Regions: [] } 我刚刚编辑了这篇文章。谢谢。
  • 唯一有意义的是data.Regions 是一个对象数组,每个对象都有.RegionName.Endpoint 属性,但winston 的.info() 似乎做得很好隐藏对象{} 结构并使data.Regions 看起来像一个平面数组。对吗?
  • 有可能。但我想弄清楚的是,为什么在每个区域解析所有弹性 IP 请求的结果是相同的,并且在数组点之间具有相同的值,因为我知道我在一个区域中只有一个弹性 IP。
  • 好吧,我不明白问题中的所有内容,但简单的答案似乎是 ec2Addresses.describeAddressesPromised() 没有提供您期望的数据,可能是因为表达式 _.create(ec2, {region: region.RegionName}) 在某种程度上不正确.

标签: node.js amazon-ec2 promise bluebird aws-sdk


【解决方案1】:

我发现了问题。 正如@Roamer-1888 所示,ec2Addresses 对象的创建不正确。相反,我应该使用 AWS 开发工具包构造函数为 EC2 对象创建一个新实例。然而,问题的关键是另一个问题。首先是代码...

logger.info('About to fetch Regions');
ec2.describeRegionsPromised({}).then(function (data) {
  var addressesPromises = [];

  logger.info('Fetched Regions');

  _.forEach(data.Regions, function (region) {
    var ec2Addresses = AWS.ec2(
      {
        region: region.RegionName,
        endpoint: region.Endpoint
      }
    );
    addressesPromises.push(ec2Addresses.describeAddressesPromised());
  });
  logger.info('About to fetch addresses per region');

  return Promise.all(addressesPromises);
}).then(function (data) {
  logger.info(arguments);
  logger.info('Fetched addresses per region');
  logger.debug(data);
}).catch(function (err) {
  logger.error('There was an error when fetching regions and addresses');
  logger.error(err);
});

正如您在此处所注意到的,ec2Addresses 是通过调用 AWS.ec2() 而不是 new AWS.ec2() 创建的,这是因为 AWS 承诺的模块创建了对象并将其返回以承诺它。 (https://github.com/davidpelayo/aws-promised/blob/master/ecs.js):

'use strict';

var AWS = require('aws-sdk');
var memoize = require('lodash/function/memoize');
var promisifyAll = require('./lib/util/promisifyAll');

function ecs(options) {
  return promisifyAll(new AWS.ECS(options));
}

/**
 * Returns an instance of AWS.ECS which has Promise methods
 * suffixed by "Promised"
 *
 * e.g.
 * createService => createServicePromised
 *
 * @param options
 */
module.exports = memoize(ecs);

问题出在最后一行代码: module.exports = memoize(ecs) 这行代码正在缓存先前的执行,包括其先前的配置

事实证明,我最终调试了应用程序,我意识到正在执行的承诺数组的区域和端点是相同的,并且那里出现了错误。

通过删除memoize(ecs),预期的结果就是我得到的结果:

info: Fetched addresses per region
debug:  Addresses=[], Addresses=[], Addresses=[], Addresses=[], Addresses=[], Addresses=[PublicIp=XX.XXX.XXX.XXX, AllocationId=eipalloc-XXXXXX, Domain=vpc], Addresses=[], Addresses=[], Addresses=[]

感谢您的阅读和帮助。

【讨论】:

    【解决方案2】:

    我找到了一种无需创建新的 EC2 对象即可请求不同区域地址的方法。换句话说,通过重用现有的 EC2 实例,通过如下方式切换端点:

    _.forEach(data.Regions, function (region) {
        //var ec2Addresses = AWS.ec2(
        //  {
        //    region: region.RegionName,
        //    endpoint: region.Endpoint
        //  }
        //);
        var ep = new AWS.Endpoint(region.Endpoint);
        ec2.config.region = region.RegionName;
        ec2.endpoint = ep;
        addressesPromises.push(ec2.describeAddressesPromised());
      });
      logger.info('About to fetch addresses per region');
    

    【讨论】:

      猜你喜欢
      • 2015-10-23
      • 1970-01-01
      • 2015-03-04
      • 1970-01-01
      • 2021-01-11
      • 1970-01-01
      • 1970-01-01
      • 2017-03-27
      • 2018-04-07
      相关资源
      最近更新 更多