EC店舗のService Bus設計をClaude Codeで整理する: 注文、在庫、再送の分け方
EC店舗向けにAzure Service Busのqueue、topic、DLQ、重複検知を注文と在庫で分けます。
EC店舗の受注画面で、注文CSV、在庫CSV、メール送信ログ、再送メモが別々に残っていると、障害時にどこから直すか分からなくなります。注文確定を再送しただけなのに在庫が2回減り、発送依頼だけ止まり、購入者メールは届いたように見える。今日まず直す1箇所は、注文、在庫、メール、再送を同じqueueに入れないための分け方表です。
この記事では、EC店舗の注文処理をAzure Service Busで分ける前に、Claude Codeで設計メモを作る流れを書きます。対象は、モール受注CSV、在庫管理CSV、発送依頼、確認メール、失敗時の再送ログを見ているEC担当者です。Azure Service Busのqueue、topic/subscription、dead-letter queue、duplicate detectionを、注文と在庫の現場語に置き換えます。
参考にした一次情報は、Service Bus overview、queues, topics, and subscriptions、dead-letter queues、duplicate detection、message transfers, locks, and settlement、Service Bus pricing tiersです。Azure連携の考え方は、士業事務所のAzure OpenAI導入メモともつながります。
この記事の要点
- EC店舗では、注文確定、在庫引き当て、発送依頼、確認メール、再送を1つのqueueに混ぜない。
- queueは「1種類の作業を1つの担当が処理する箱」、topic/subscriptionは「注文確定を在庫、発送、メールへ分ける分岐」と見る。
- duplicate detectionは、注文ID、明細行ID、処理名から作ったMessageIdで見る。毎回ランダムなIDにすると再送の重複を止めにくい。
- dead-letter queueは失敗メッセージの避難場所です。全部を自動再送せず、原因、直し方、再投入者を表にする。
- Claude Codeには、注文フロー、CSV列名、イベント名、再送ログを読ませる。決済、返金、個人情報、在庫確定、公開承認は人が見る。
ECの注文フローで起きる失敗シーン
EC担当者が見ている画面は、受注一覧、在庫表、発送システム、メール配信ログ、決済管理画面です。注文確定後に在庫を減らし、倉庫へ発送依頼を出し、購入者へ確認メールを送る。この流れのどこかが落ちた時、全部を同じ再送ボタンで戻すと事故が出ます。
よくあるのは、メールだけ失敗したのに注文確定イベントごと再送してしまい、在庫引き当てまで2回走るパターンです。別の例では、在庫引き当てが失敗してdead-letter queueに入ったのに、原因を見ずに再投入してまた落ちます。商品SKUの廃番、明細行IDの欠落、数量の0、発送対象外の商品など、直す場所はメッセージごとに違います。
Service Busのドキュメントでは、queueは受信側が処理できるまでmessageを保持し、topic/subscriptionはpublish/subscribeの分岐に使うと説明されています。dead-letter queueは処理できなかったmessageを調べるための場所で、duplicate detectionはMessageIdを指定時間だけ記録し、重複messageを受け付けたように見せながら保存しない仕組みです。2026年9月30日には古いService Bus SDKとSBMP protocolのサポート終了も告知されています。いま設計メモを直す意味は十分あります。
Claude Codeに任せる範囲と人が見る範囲
注文CSVと在庫CSVを前にして、Claude Codeに任せるのはイベント分解です。注文確定、在庫引き当て、発送依頼、メール送信、キャンセル、返金、再送、DLQ確認を表にします。表の列は、イベント名、入力列、送信先、MessageId、失敗時の置き場所、再送してよい条件、人の確認です。
人が見る範囲は、決済状態、返金可否、個人情報、倉庫との契約、在庫確定、購入者への謝罪文、再送承認です。Claude Codeは「この明細は在庫を減らすべき」と判断しません。代わりに「在庫を減らす前に、注文ID、明細行ID、SKU、数量、決済状態が必要」といったチェック表を作らせます。
Azure側では、Basic tierにはtopicsやduplicate detectionがない点も見ます。注文確定を在庫、発送、メールへ分けたいなら、StandardまたはPremiumの機能を前提にする必要があります。Premiumはresource isolationや大きいmessageサイズが必要な場面で候補になりますが、最初の記事内設計では、まずmessageを小さくし、画像や帳票本体はBlob Storageなどへ置き、Service Busには参照IDを送る方針にします。
3つのUse case
Use case 1: 注文確定を在庫、発送、メールに分ける
- 入力: 受注CSV、注文ID、明細行ID、SKU、数量、決済状態、購入者メール送信要否。
- 出力: topic:orders と、inventory-reserve、shipping-request、mail-send のsubscriptionまたはqueue設計表。
- 人の確認: 決済未確定、予約商品、同梱、ギフト、手動在庫調整、メール文面を見る。
注文確定イベントは、在庫だけの話ではありません。倉庫、メール、分析、CRMが同じ注文を見たい場面があります。Claude Codeには「注文確定はtopicへ出し、各subscriptionで目的別に受ける」と整理させます。人は、どのsubscriptionが失敗した時に注文全体を止めるか、どれは後追いでよいかを決めます。
Use case 2: 在庫引き当ての重複をMessageIdで見る
- 入力: 注文ID、明細行ID、SKU、数量、在庫引き当て処理名、送信ログ。
- 出力: MessageId命名表。例は orderId + lineItemId + reserve のような業務キー。
- 人の確認: 同じ注文の数量変更、キャンセル後の再注文、セット商品の分解、在庫戻しを見る。
duplicate detectionは便利ですが、魔法の二重処理防止ではありません。Azure Service BusはMessageIdを見ます。送信側が毎回ランダムなIDを入れると、同じ在庫引き当てを別messageとして扱いやすくなります。Claude Codeには、在庫を減らす処理ごとに安定したMessageId案を出させ、人が数量変更やキャンセルの扱いを確認します。
Use case 3: dead-letter queueの再送ルールを表にする
- 入力: DLQのreason、description、注文ID、SKU、失敗回数、最後に失敗した時刻、担当者メモ。
- 出力: 自動再送、人が直して再送、注文保留、返金確認、開発調査の5分類表。
- 人の確認: 購入者連絡、返金、在庫差異、倉庫への連絡、再送ボタンを押す権限を見る。
dead-letter queueは、落ちたmessageを捨てる箱ではありません。原因を見て直すための待避場所です。SKUが存在しない、数量が0、住所の必須項目がない、倉庫APIが一時停止、message schemaが古い。原因が違えば再送の判断も違います。Claude Codeには、DLQ一覧から分類表を作らせ、人は購入者に影響する判断を止めます。
コピペで使えるプロンプト
あなたはEC店舗のAzure Service Bus設計メモ作成担当です。
目的は、注文、在庫、発送、メール、再送を1つのqueueに混ぜず、事故が起きた時に人が直せる表を作ることです。
入力:
- 受注CSVの列名
- 在庫CSVの列名
- 現在のイベント名またはバッチ名
- 再送ログのサンプル
- DLQ reason / description のサンプル
- 使う予定のAzure tier
出力:
1. イベント一覧表: eventName / 入力列 / queue or topic / subscription / MessageId / 失敗時の置き場所
2. 人が見る表: 決済、返金、個人情報、在庫確定、購入者連絡、再送承認
3. MessageId命名案: 注文ID、明細行ID、処理名から作る
4. DLQ分類表: 自動再送、人が直して再送、注文保留、返金確認、開発調査
5. 本番前チェック: Basic/Standard/Premiumの前提、古いSDK利用有無、ログに個人情報を残さない方針
制約:
- 決済、返金、個人情報、在庫確定をAI判断にしない
- message本文にカード情報や住所全文を入れない
- 再送は全部自動にしない
- まず30分で直す1箇所を最後に1つだけ出す
動く確認コード
注文CSVをそのままAzureに投げる前に、ローカルでevent名、MessageId、未知のrouteを見ます。次のコードは、重複MessageId、注文ID欠落、未設計routeを検出します。実Azureには接続しないので、設計レビュー用の小さな前処理として使えます。
const events = [
{ type: "order.accepted", orderId: "ORD-1001", lineItemId: "1", sku: "TSHIRT-M", quantity: 2, action: "accept" },
{ type: "inventory.reserve", orderId: "ORD-1001", lineItemId: "1", sku: "TSHIRT-M", quantity: 2, action: "reserve" },
{ type: "inventory.reserve", orderId: "ORD-1001", lineItemId: "1", sku: "TSHIRT-M", quantity: 2, action: "reserve" },
{ type: "mail.send", orderId: "ORD-1001", lineItemId: "", sku: "", quantity: 0, action: "confirmation" },
{ type: "inventory.reserve", orderId: "", lineItemId: "2", sku: "MUG-BLUE", quantity: 1, action: "reserve" },
{ type: "shipping.requested", orderId: "ORD-1002", lineItemId: "1", sku: "BAG-BK", quantity: 1, action: "ship" }
];
function routeEvent(event) {
if (event.type === "order.accepted") {
return {
entity: "topic:orders",
messageId: event.orderId + ":accepted",
reason: "fan out to inventory, shipping, mail, and analytics subscriptions"
};
}
if (event.type === "inventory.reserve") {
return {
entity: "queue:inventory-reserve",
messageId: event.orderId + ":" + event.lineItemId + ":reserve",
reason: "one stock reservation worker should own this line item"
};
}
if (event.type === "mail.send") {
return {
entity: "queue:mail-send",
messageId: event.orderId + ":" + event.action,
reason: "mail can retry without touching stock"
};
}
return {
entity: "needs-design-review",
messageId: event.orderId + ":" + event.type,
reason: "route is not documented yet"
};
}
const seen = new Set();
const findings = [];
for (const event of events) {
const route = routeEvent(event);
if (!event.orderId) {
findings.push({
type: "missing-order-id",
eventType: event.type,
fix: "do not send this message until the order id is present"
});
}
if (seen.has(route.messageId)) {
findings.push({
type: "duplicate-message-id",
eventType: event.type,
messageId: route.messageId,
fix: "keep the same MessageId for sender retry, but make the handler idempotent"
});
}
if (route.entity === "needs-design-review") {
findings.push({
type: "unknown-route",
eventType: event.type,
fix: "decide queue, topic subscription, DLQ owner, and retry rule before release"
});
}
seen.add(route.messageId);
}
console.table(findings);
if (findings.length > 0) process.exitCode = 1;
この出力にduplicate-message-idが出たら、送信側retryで同じMessageIdを使っているのか、在庫引き当て処理が本当に二重に走る危険があるのかを分けて確認します。unknown-routeが出たら、queueに入れる前に、担当者、DLQ、再送条件を表へ足します。
Pitfall: よくある落とし穴
原因: 注文、在庫、メールを1つのqueueに入れる。直し方: 注文確定はtopic、在庫引き当てはqueue、メールは別queueに分け、失敗時に戻す場所を別にします。メール障害で在庫を触らない線を先に引きます。
原因: MessageIdを毎回ランダムに作る。直し方: 在庫を減らす処理は、注文ID、明細行ID、処理名からMessageIdを作ります。送信失敗でretryした時に同じMessageIdになるよう、送信前にIDを確定します。
原因: DLQを全部まとめて再送する。直し方: reasonごとに、自動再送、人が直して再送、注文保留、返金確認、開発調査へ分けます。購入者連絡や返金が絡むmessageは、人が見てから戻します。
原因: tier差を見ずに設計する。直し方: topics、transactions、de-duplication、sessionsが必要ならBasicではなくStandard以上の前提にします。Premiumが必要かは、負荷、分離、message size、運用時間で後から見ます。
よくある質問
Q. ECなら全部topicでよいですか? A. 注文確定のように複数の処理へ分けたいeventはtopicが合います。一方で、在庫引き当てやメール送信のように1つの担当が順番に処理する作業はqueueの方が読みやすいです。
Q. duplicate detectionを入れれば在庫の二重減算は消えますか? A. MessageIdが安定している範囲では助けになります。ただしhandler側も、同じ注文明細を2回処理しても壊れないように、処理済み記録を見る必要があります。
Q. DLQは開発者だけが見るものですか? A. 違います。ECでは購入者連絡、在庫差異、返金、倉庫連絡が絡みます。開発者だけで再送せず、運用担当が読めるreason表にします。
Q. message本文にはどこまで入れますか? A. 注文ID、明細行ID、SKU、数量、参照IDを中心にします。住所全文、カード情報、問い合わせ本文のような個人情報は、必要性とログ方針を人が見てから決めます。
研修・相談につなげるなら何を見るか
EC店舗でAzure Service Busを入れる相談は、クラウド構成だけでは終わりません。受注CSV、在庫CSV、発送依頼、メール文面、再送ログ、返金フローまで並べないと、現場の事故は減りません。Claude Codeに任せるなら、まず設計表、MessageId表、DLQ分類表、本番前チェックリストを作らせるのが現実的です。
このあたりを自社の受注フローに合わせて一緒に整理したい場合は、Claude Code研修・相談で、注文フロー、権限、ログ、再送ルールを題材にできます。相談前に持ってくるものは、受注CSVの列名、在庫CSVの列名、失敗ログ3件、現在の再送手順だけで十分です。
実際に試した結果
この記事では、Azureリソースを作らず、Service Bus公式資料、queue/topic/DLQ/duplicate detectionの整理、記事内のJavaScript確認コード、内部リンク、CTA、frontmatter、slugを確認しました。コードは注文ID欠落、重複MessageId、未設計routeを検出します。今日まずやる1手は、受注CSVの列名をコピーし、注文、在庫、メール、再送を1枚の表に分けることです。
次に読む記事
士業事務所のAzure Functions小さな自動化をClaude Codeで作る: 相談フォーム通知から始める
士業向けにAzure Functionsで相談フォーム通知を作る前の個人情報、secret、失敗通知を点検します。
士業事務所のAzure OpenAI Service導入メモをClaude Codeで作る: 個人情報を入れない社内FAQ
士業事務所向けに社内FAQ、個人情報、RBAC、content filter、ログ方針を確認します。
EC店舗がBicepテンプレートをClaude Codeで読む: 小さな会社のIaC安全確認
EC店舗向けにBicepのscope、secret、what-if、公開設定、rollbackを確認します。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。