Shopifyと外部システムをつなぐとき、「Webhookで連携する」と一言で片付けられがちですが、実務ではデータの流れる向きによって適切な方式が変わります。注文はWebhook、在庫はバッチ。これは怠慢な設計ではなく、それぞれの性質から導かれる合理的な使い分けです。そして受信側のWebhookには、守らないと確実に事故る鉄則があります。本記事では、連携方式の選び方と、Webhook受信の設計原則、そして意外に軽視されがちなキー設計について整理します。Shopifyと倉庫・基幹・外部サービスをつなぐ設計に関わる技術者、そして連携の見積もりを読む立場のPMに向けた内容です。
注文はWebhook、在庫はバッチ
まず使い分けの結論から。ある案件で外部の倉庫管理システムとShopifyを双方向でつないだとき、方式は次のように分かれました。
在庫(外部システム → Shopify)はバッチ。15分程度の周期で、外部システム側が実在庫数を取得してShopifyの在庫を更新します。
注文(Shopify → 外部システム)はWebhook。新規注文・注文変更・キャンセルをイベント駆動で連携します。
出荷完了(外部システム → Shopify)はAPI呼び出し。出荷後に追跡番号を含むフルフィルメント情報を更新し、Shopifyから出荷完了メールが自動送信される流れに乗せます。
この非対称はどこから来るのか。注文は出荷の起点であり、遅延が許されないからWebhookです。一方、在庫は「今この瞬間の正確な値」よりも「定期的に真値へ収束すること」のほうが重要です。倉庫での入出庫は1件ずつイベントとして流すには粒度が細かすぎるうえ、途中で1件取りこぼすと在庫がずれたまま復旧しません。定期的に実在庫を丸ごと反映する方式なら、たとえ一度失敗しても次の周期で自然に正しい値へ戻ります。
つまり、イベントの取りこぼしが致命傷になるものはバッチで冪等に、遅延が致命傷になるものはWebhookで、という判断軸です。ここを逆にすると、リアルタイム在庫のためにWebhookを積み上げた結果、ズレが蓄積して誰も直せない、という典型的な失敗に至ります。
Webhook受信の鉄則は「すぐ返して、後でやる」
Webhookを受ける側には、Shopifyに限らず共通する鉄則があります。受信したら数秒以内に成功レスポンスを返し、実際の処理は後回しにすることです。
Shopifyは応答が一定時間(数秒程度)返らないと配信失敗とみなして再送します。受信ハンドラの中で通知を送ったり、外部APIを叩いたり、重い集計をしたりすると、その処理が遅いだけで再送が始まり、同じ注文が二重に処理される事故につながります。
当社が標準としている構成は次の流れです。
まず署名検証。届いたリクエストが本当にShopifyから来たものかをHMACで確認します。これは本人確認にあたる工程で、省略はできません。
次にキューへ退避。検証が済んだら、やるべき仕事の内容をキューに入れ、Shopifyには即座に成功を返します。ここまでが受付係の仕事です。
そして別プロセスで処理。キューから取り出した仕事を、別の関数が処理します。設定を読み、外部システムを呼び、結果を書き戻す。ここで時間がかかっても失敗しても、Shopifyへの応答には影響しません。仕事はキューに残っているので、リトライも効きます。
この構成の価値は、受付と実作業を分離することで外部要因の遅延がShopifyへの応答に伝播しない点にあります。連携先が増えるほど、この分離の恩恵は大きくなります。
キューまわりで決めておくべき既定値
キューを挟む構成にすると、今度はキューの設定が効いてきます。当社がテンプレートに焼き込んでいる既定値は次のとおりです。
可視性タイムアウトは処理関数のタイムアウトの2倍以上。ここが短いと、まだ処理中のメッセージが別のワーカーにも配られ、二重実行になります。
デッドレターキューを必ず用意し、保持期間は長めに、再試行回数は数回で打ち切る。失敗したメッセージを永久にリトライさせると、1件の毒メッセージがキュー全体を詰まらせます。
デッドレターキューの滞留を監視してアラートを飛ばす。これが最重要です。外部連携の障害でもっとも怖いのは、壊れたことに誰も気づかないまま数日が経つケースだからです。滞留件数が0を超えたら通知する、という単純なアラートで防げます。
冪等性キーを必須にする。Webhookは仕様上、同じイベントが複数回届き得ます。「一度処理したイベントIDは二度処理しない」という記録を持つのは、あれば良い機能ではなく前提条件です。
見落とされがちな主役はキー設計
連携方式の議論に比べて驚くほど軽視されるのが、システム間で対象を特定する共通キーをどう決めるかです。しかし実務では、ここが全体の成否を握ります。
ある案件では、商品を識別する業界標準の識別番号を全システムを貫くキーに据えました。クライアントの販売リスト、倉庫管理システム、外部の商品情報データベース、そしてShopifyのSKU。すべてが同じ番号で突合します。この設計にすると、在庫連携も注文連携もSKUをキーに自動で噛み合い、商品の詳細情報も外部データベースから自動で引けるので、商品登録の手入力がほぼ不要になります。
裏を返すと、SKUに正しい値が入っていないと、在庫も出荷も何ひとつ動きません。連携先の実装がどれだけ堅牢でも、キーが合っていなければ全滅です。カート側の担当範囲が「SKUを正しく設定すること」だけに見えて、実はそこが全連携の生命線になっている、という構造です。
見積もりの場でも、この点は言語化しておく価値があります。「ただのCSVを受け取るだけ」に見える工程が、実は在庫連携・データ取得・出荷連携すべての起点である、という説明ができるかどうかで、その工程に割く工数への納得感が変わります。
受け渡しの導線は、アプリの管理画面に置く
外部から連携用のリストを受け取るとき、メールやチャットでファイルをやり取りする運用は必ず破綻します。誰がいつ何を送ったか分からなくなり、フォーマット違いが混ざり、エラーが起きても本人に伝わりません。
当社では、連携用のカスタムアプリに管理画面を持たせ、そこにアップロード導線を置くようにしています。クライアント自身がファイルを上げると、その場で外部データベースから情報を取得して下書き商品を生成し、アップロード履歴とエラー行(データが見つからなかった行など)を画面上で確認できる。これでクライアント側のセルフサービスで完結し、こちらへの連絡も不要になります。
ただし設計上の注意が1点。既存データの差分を更新する定期バッチとは別に、オンデマンドの生成トリガーが増える形になります。この2系統が同じデータを触る以上、競合や上書きの順序を決めておく必要がありますし、見積もりの機能範囲との整合も確認が要ります。「便利だから付けよう」で追加すると、後で整合性のバグとして返ってきます。
公開のタイミングをどう扱うか
もうひとつ、連携設計から自然に浮かび上がる論点があります。外部データから商品を自動生成する場合、その時点では実在庫がまだ倉庫に届いていないことが普通です。
そこで基本は下書きステータスで登録し、在庫が反映されてから公開に切り替えます。ただしこれは技術の問題ではなく、商品公開ポリシーの問題です。在庫が付くまで見せないのか、在庫0でも「入荷待ち」として先に公開するのか。前者なら公開切替の工程が必要になり、自動化するか手運用にするかの判断も要ります。後者なら工程自体が消えます。
連携方式の話をしているつもりが、実は業務の意思決定を求めている。この種の論点は早めに表に出して、クライアントに選んでもらうのが結局いちばん速く進みます。
まとめ
Shopifyと外部システムの連携は、向きと性質で方式が決まります。遅延が致命傷になる注文はWebhook、取りこぼしが致命傷になる在庫はバッチ。Webhookを受ける側は、署名を検証してキューに逃がし、すぐ成功を返す。可視性タイムアウト、デッドレターキュー、その滞留監視、冪等性キーは、あとから足すものではなく最初から入れておくものです。そして意外に主役なのがキー設計で、システム間を貫く識別子が正しく入っているかが全連携の生命線になります。連携の議論では方式の話が盛り上がりがちですが、キーと公開ポリシーという地味な2点を先に固めるほうが、結果的にプロジェクトを速く進めます。

