0

我在几天前列出的 Shopify 应用上遇到了一个大问题。我的应用程序的核心功能是访问 Shopify API 端点以多次编辑 draft_orders 的端点。我完全清楚每分钟 40 个请求的速率限制和每秒 2 个请求的刷新率。

奇怪的是这些失败请求的时间戳:

PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [429] 09:09:16
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [429] 09:09:18
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [429] 09:09:23
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [429] 09:09:31
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [429] 09:09:47
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [429] 09:10:19

所有这些都返回:

Error code: 429 (Too many request)
Error message: REASON: Exceeded 2 calls per second for api client. Reduce request rates to resume uninterrupted service.
Copy 

如您所见,第一个失败的请求和最新的请求之间有超过 1 分钟的时间。所以我完全不知道是什么导致了这个问题。

编辑

我想我可能发现了问题。我(错误地)假设用户只会发出一个请求并等待该请求完成,然后再发送另一个请求。因此,这是我在端点中的代码:

const handleGetRequest = async (req, res) => {
  const {shop, accessToken} = await Shopify.Utils.loadCurrentSession(
    req,
    res
  );

  const client = getShopifyClient(shop, accessToken);
  
  // do stuff with Shopify client

}

在哪里getShopifyClient

const getShopifyClient = (shopName, accessToken) => {
  const shopify = new Shopify({
    autoLimit: { calls: 1, interval: 1100, bucketSize: 30 },
    shopName: shopName,
    accessToken: accessToken,
  });

  shopify.on("callLimits", (limits) =>
    console.log(
      `CURRENT API LIMIT STATE: ${util.inspect(
        limits,
        false,
        null,
        true /* enable colors */
      )}`
    )
  );

  shopify.on("callGraphqlLimits", (limits) =>
    console.log(
      `CURRENT API LIMIT STATE: ${util.inspect(
        limits,
        false,
        null,
        true /* enable colors */
      )}`
    )
  );

  return shopify;
};

现在我意识到,每次我收到新请求时,这段代码都会创建一个 Shopify 类的新实例(尽管来自同一个用户,具有相同的商店名称和访问令牌)。

如果是这种情况,getShopifyClient如果我发送相同的商店名称,是否可以记住返回相同的实例?像这样的东西:

let memoizedClient = {}
const getShopifyClient = (shopName, accessToken) => {
  if (memoizedClient[shopName]) {
     return memoizedClient[shopName]
  }
  const shopify = new Shopify({
    autoLimit: { calls: 1, interval: 1100, bucketSize: 30 },
    shopName: shopName,
    accessToken: accessToken,
  });

  shopify.on("callLimits", (limits) =>
    console.log(
      `CURRENT API LIMIT STATE: ${util.inspect(
        limits,
        false,
        null,
        true /* enable colors */
      )}`
    )
  );

  shopify.on("callGraphqlLimits", (limits) =>
    console.log(
      `CURRENT API LIMIT STATE: ${util.inspect(
        limits,
        false,
        null,
        true /* enable colors */
      )}`
    )
  );

  memoizedClient[shopName] = shopify

  return shopify;
};

你怎么看?

4

1 回答 1

0

仅通过检查这些错误来推断429s 原因不足以解释它们!在您发布的日志中,成功的请求不会与失败的请求一起显示。那么,在您不知情的情况下,成功的请求正在用完配额,这不是合理的吗?也许您包含成功请求和失败请求的日志可能看起来更像这样?

PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [429] 09:09:16
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [200] 09:09:16
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [200] 09:09:16
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [200] 09:09:17
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [200] 09:09:17
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [200] 09:09:18
PUT https://****.myshopify.com/admin/draft_orders/124016722005.json [429] 09:09:18
... and so on

我看到您将 Q 标记为shopify-api-node,因此请考虑在库的构造函数上使用该autoLimit选项shopify-api-node

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

此外,该callLimits事件可能是一个有用的调试/弹性工具。

于 2021-11-25T15:52:43.700 回答