使用Promise.all的异步等待和瓶颈速率限制

时间:2019-04-01 17:08:56

标签: node.js promise async-await intercom

我使用的API的速率限制为每分钟500个请求。 因此,我决定使用bottleneck。但是我需要执行异步函数数组,该函数会生成一个Promise来进行该API调用。我不确定我的方法是否正确。因为API会以“超出10秒内83的最大速率限制”响应我,而我在10秒内仅发送70个请求。

这是我调用主函数的方式:

const result = await Helper.updateUsers(request.query.where);
..
..

这是helper.js

const Boom = require("boom");
const mongoose = require("mongoose");
const Bottleneck = require("bottleneck");

const Intercom = require("intercom-client");

const config = require("../../config/config");

const client = new Intercom.Client({
  token: config.intercom.access_token
});

const User = mongoose.model("User");
const Shop = mongoose.model("Shop");

// create a rate limiter that allows up to 70 API calls per 10 seconds,
// with max concurrency of 70
const limiter = new Bottleneck({
  maxConcurrent: 70,
  minTime: 10000
});

// Helpers

// This function prepares a valid Intercom User Object.
// user -> User Object
// returns <Promise>
const prepareAndUpdateUser = async user => {
  try {
    let userData = {
      email: user.email,
      user_id: user._id,
      companies: []
    };
    Shop.find({ _id: { $in: user.account.shops } })
      .exec((err, shops) => {
        if (err) console.log("INTERCOM UPDATE USER", err);
        shops.forEach(shop => {
          let shopData = {
            company_id: shop._id,
            name: shop.name[shop.defaultLanguage.code]
          };
          userData.companies.push(shopData);
        });
        // Update Intercom Promise
        return client.users.create(userData);
      });
  } catch (e) {
    return Boom.boomify(err);
  }
};

module.exports.updateUsers = async query => {
  try {
    const users = await User.find(query)
      .populate("account")
      .limit(700);
    if (users && users.length > 0) {
      limiter.schedule(() => {
        const allTasks = users.map(
          async user => await prepareAndUpdateUser(user)
        );
        return Promise.all(allTasks);
      });
      return users.length;
    } else {
      return 0;
    }
  } catch (err) {
    return Boom.boomify(err);
  }
};

我使用Bottleneck和Async-Await正确吗?

1 个答案:

答案 0 :(得分:1)

要指出的第一件事是您在public class ZoomCommand extends Command { Image image; Memento memento public InsertCharacterCommand(Image image) { //instantiate this.image = image; } @Override public void execute() { //create Memento before executing memento = new Memento(); // set the initial zoom level of the image before executing memento.setState(image); //set new state image.zoomIn(image.getZoom() + 1); } @Override public void unExecute() { // redo go back to initial state of image before zoom, but image has the same zoom level this.image = memento.getState(); } } 方法中使用回调,而不是async作出承诺。您应该使用await的承诺返回版本和Shops.find()的结果。

await

在您的async function prepareAndUpdateUser(user) { try { const shops = await Shop.find({ _id: { $in: user.account.shops } }).exec(); return client.users.create({ email: user.email, user_id: user._id, companies: shops.map(shop => { return { company_id: shop._id, name: shop.name[shop.defaultLanguage.code] }; }) }); } catch (e) { return Boom.boomify(err); } } 方法中,您向后使用速率限制器。您希望将用户映射到速率限制器中,以便它可以控制何时调用updateUsers,当前您将并行请求所有内容。您还想等待速率限制器返回的承诺解决。本质上,您将需要将prepareAndUpdateUser移至limiter.scehdule(...)

user.map(...)