GraphQL Admin API の Throttled エラーに遭遇した話

はじめに

Shopify アプリ開発において GraphQL Admin API を利用することは往々にしてあるでしょう。

注文や商品情報などShopifyが管理しているデータを取得できる便利なAPIだが、利用し放題というわけではありません。

2024年1月現在では60秒間に1,000ポイントまでの上限が設けられており、それを超えると APIの実行がエラーとなってしまいます。( ポイントの計算については割愛 )

最近この上限に引っかかる事案に遭遇したので、そのケースと対応をまとめていきます。

発生ケース

Shopifyアプリ開発エンジニアにとって見たくないものの1つ、それがこれ。

Shopify GraphQL error response

週末の午後、冷蔵庫からビールを取り出してさあ飲もうとした時に飛んできたエラー通知

( 見なきゃよかった。。。 )

渋々ビールを冷蔵庫に戻し調査にあたったところ、どうも該当のAPIを単体で実行しても上限に引っかかりそうにない。

となると考えられるケースとしては、

  1. APIが重複して実行されている
  2. GraphQL Admin APIのバグ

ということで1の可能性がないか調査。

該当のAPIは Shopify の ProductUpdate Webhook をトリガーに非同期で実行されている箇所だったので Webhook が複数呼ばれたのでは?と仮説が立てられる。

これがビンゴで一度に大量の商品が更新されたことで Webhook が複数呼ばれていた模様。

考慮できてなかったが確かにあるよなこのケース、、、と思い対応にあたる。

解決策

今回問題となったのは、`商品A`の情報をとってくるGraphQL Admin APIが60秒間に何度も呼ばれてしまっていることです。

const fetchProductVariant = async() => await requestApi({ id: 商品AのID })

であれば60秒間に1回しかAPIを呼ばないようにする方法を考えれば良さそう。

そこで採用した案が`キャッシュ`させるというもの。

const cacheApiResponse = async(key, api ) => {

  const cacheExpiredAt = getCacheExpiredAt();

  const now = new Date();

 

  if ( cacheExpiredAt <= now ) {

    const response = api();

    const newExpiredAt = new Date(now.getTime() + 60 * 1000)

    updateCache(key, response, newExpiredAt);

    return response;

  } else {

    const response = getCache(key);

    return response;

  }

}

上記で行なっていることは以下です。

  • 商品IDに対するAPIのレスポンス値をキャッシュDBで管理
  • 前回のキャッシュデータ更新から1分以内であればキャッシュDBを参照
  • そうでなければAPIから取得

これでエラーは解決しました

まとめ

GraphQL Admin APIを例に出しましたが、Storefront API や Rest Admin API においても実行上限は設けられているので、同様の解決策が取れるだろうと思います。

エラーの発生は心臓に良くないので安全なアプリ開発ライフを送っていきましょう!