如何使用微应用 Node.js 模块处理 Shopify 的 API 调用限制

How to handle Shopify's API call limit using microapps Node.js module

我一直在努力寻找这个问题的答案,我就是想不通。我正在为 microapps 的 Shopify API 使用 Node.js 模块。我有一个 JSON object,其中包含我需要更新的产品 ID 和 skus 列表,因此我遍历该文件并调用调用 api 的函数。 Shopify 的 API 限制了对它的调用并发送一个响应 header 和剩余的值。该节点模块提供了一个包含限制和用法的 object。我的问题是基于下面的代码,当我达到限制时如何在 setTimeout 或类似的地方。一旦您拨打了第一个电话,它将 return 限制 object 如下所示:

{
 remaining: 30,
 current: 10,
 max: 40
}

这是我在不遵守限制的情况下所拥有的,因为我尝试的一切都失败了:

const products = JSON.parse(fs.readFileSync('./skus.json','utf8'));

for(var i = 0;i < products.length; i++) {
  updateProduct(products[i]);
} 

function updateProduct(product){
    shopify.productVariant.update(variant.id, { sku: variant.sku })
    .then(result => cb(shopify.callLimits.remaining))
    .catch(err => console.error(err.statusMessage));
} 

我知道我需要实施某种回调来检查剩余使用量是否很低,然后等待几秒钟再调用。任何帮助将不胜感激。

如果您查看 Shopify 代码,他们的 github 存储库有一个 CLI。该 CLI 正在处理这些限制。您可以快速了解 Shopify 如何处理这些限制,查看他们的代码。

由于他们的代码在 Ruby 中,因此很容易理解。一个熟练的 JS 程序员不应该花费超过几分钟的时间来了解如何基于此代码处理限制,甚至从 Ruby 中抽象出来。

所以我的建议是阅读 Shopify 代码并尝试修改您的 JS 代码以匹配相同的模式。

我会使用一些东西来限制 shopify-api-node (Shopify.prototype.request) 用来创建请求的函数的执行率,例如 https://github.com/lpinca/valvelet.

下面的代码未经测试,但应该可以工作。它应该遵守每秒 2 次调用的限制。

var Shopify = require('shopify-api-node');
var valvelet = require('valvelet');

var products = require('./skus');

var shopify = new Shopify({
  shopName: 'your-shop-name',
  apiKey: 'your-api-key',
  password: 'your-app-password'
});

// Prevent the private shopify.request method from being called more than twice per second.
shopify.request = valvelet(shopify.request, 2, 1000);

var promises = products.map(function (product) {
  return shopify.productVariant.update(product.id, { sku: product.sku });
});

Promise.all(promises).then(function (values) {
  // Do something with the responses.
}).catch(function (err) {
  console.error(err.stack);
});

尝试使用 autoLimit 选项,例如:

import Shopify from 'shopify-api-node';

const getAutoLimit = (plan: string) => {
  if (plan === 'plus') {
    return { calls: 4, interval: 1000, bucketSize: 80 };
  } else {
    return { calls: 2, interval: 1000, bucketSize: 40 };
  }
};

const shopify = new Shopify({
  shopName: process.env.SHOPIFY_SHOP_NAME!,
  apiKey: process.env.SHOPIFY_SHOP_API_KEY!,
  password: process.env.SHOPIFY_SHOP_PASSWORD!,
  apiVersion: '2020-07',
  autoLimit: getAutoLimit(process.env.SHOPIFY_SHOP_PLAN),
});

export default shopify;

根据the library's documentation

- `autoLimit` - Optional - This option allows you to regulate the request rate
  in order to avoid hitting the [rate limit][api-call-limit]. Requests are
  limited using the token bucket algorithm. Accepted values are a boolean or a
  plain JavaScript object. When using an object, the `calls` property and the
  `interval` property specify the refill rate and the `bucketSize` property the
  bucket size. For example `{ calls: 2, interval: 1000, bucketSize: 35 }`
  specifies a limit of 2 requests per second with a burst of 35 requests. When
  set to `true` requests are limited as specified in the above example. Defaults
  to `false`.

这是我试过的版本:"shopify-api-node": "^3.3.2"

关于速率限制,参考Shopify's documentation

试试这个...

const Shopify = require("shopify-api-node");

const waitonlimit = 2;
let calllimitremain = 40;

const shopify = new Shopify({
  shopName: process.env.SHOPIFY_URL,
  apiKey: process.env.SHOPIFY_KEY,
  password: process.env.SHOPIFY_PWD,
  autoLimit: true,
});

shopify.on("callLimits", (limits) => {
  calllimitremain = limits.remaining;
  if (limits.remaining < 10) {
    console.log(limits);
  }
});

exports.update = async () => {
  //Run this before update
  while (calllimitremain <= waitonlimit) {
    shopify.product.list({ limit: 1, fields: "id, title" });
    console.log(`Waiting for bucket to fill: ${calllimitremain}`);
  }

  //update
  await shopify.productVariant.update(
    onlineVariantId,
    { compare_at_price: price, price: promo }
  );
};