物流会社のPub/Sub設計をClaude Codeで整理する: 遅延通知と再送の落とし穴
物流会社向けにPub/Sub、遅延通知、再送、DLQ、冪等性をClaude Codeで整理する手順です。
運送会社の配車表では、到着予定時刻だけが少し遅れたように見えても、荷主にはLINE、メール、電話、管理画面の通知が同時に走ります。ここでPub/Subの再送を雑に扱うと、同じ遅延連絡が2回届いたり、古い見込み時刻をあとから送ったりします。荷主から見ると「どれが正しいのか分からない」状態です。
この記事では、物流会社がGoogle Cloud Pub/Subで遅延通知を扱う前に、Claude Codeで設計メモ、再送ルール、DLQ、確認コードを作る手順を書きます。Pub/Subはメッセージを届ける道具です。けれど、荷主に送る文章、配車担当が見る画面、配送ステータスの順番まで決めてくれる道具ではありません。
この記事の要点
- 物流会社の遅延通知では、Pub/Subの再送より先に「同じ荷物へ何回通知してよいか」を決めます。
- Pub/Subは少なくとも1回届く前提で設計します。二重通知を止める鍵は、idempotency key、つまり同じ処理かどうかを見分ける合言葉です。
- DLQは失敗を捨てる場所ではなく、配車担当やCSがあとで見る隔離箱として扱います。
- Claude Codeには、トピック名、イベント項目、再送条件、DLQ後の人の確認表を下書きさせます。
- 研修・相談へつなげる記事では、PVよりも「問い合わせ件数」「遅延連絡のやり直し回数」「通知二重送信件数」を見ます。
現場で起きる失敗シーン
物流会社の遅延通知でよくある事故は、配車システム、倉庫の入出庫システム、ドライバーアプリ、荷主向け画面が別々に動いている時に起きます。配車担当が「16:30着を17:10着に変更」と入力し、Pub/Subへ遅延イベントを流します。通知ワーカーがメールを送り、LINEも送り、管理画面にも履歴を残します。
ここで通知ワーカーが途中で落ちると、Pub/Subは同じメッセージをもう一度届けることがあります。これは仕様上の正常な動きです。Google CloudのPub/Subドキュメントでも、サブスクライバーがackを返すまでメッセージが再配信され得る前提で説明されています。参考にした公式情報は、Pub/Sub overview、Subscriptions、Retry policy、Dead-letter topics、Exactly-once delivery、Ordering messagesです。
問題は、Pub/Subが悪いことではありません。荷主に送る通知が「再送されても壊れない形」になっていないことです。メール送信、LINE送信、荷主画面の履歴追加、配車表のステータス更新を同じ感覚で扱うと、再送のたびに外へ出る通知だけが増えます。
業務フロー: 配車表から荷主通知までを分けて見る
物流会社の画面では、配車表、便番号、荷主名、納品先、ドライバー、到着予定時刻、遅延理由、次回更新時刻が並びます。まず、この項目をPub/Subのメッセージに全部入れるかどうかを決めます。個人名や電話番号を入れすぎると、ログやDLQに残る情報が重くなります。
おすすめは、Pub/Subのイベントを「状態変更」と「外部通知」に分ける形です。状態変更イベントは、荷物ID、便番号、変更後のステータス、見込み時刻、発生元、更新者、シーケンス番号を持ちます。外部通知イベントは、送信先チャネル、テンプレートID、idempotency key、次回更新時刻、人の確認フラグを持ちます。
| 流れ | Pub/Subで見る項目 | 人が見る項目 |
|---|---|---|
| 配車表の変更 | shipmentId、status、eta、sequence | 遅延理由、荷主への説明 |
| 通知イベント作成 | idempotencyKey、channel、templateId | 送ってよい相手、送信文 |
| メール/LINE送信 | notificationId、retryCount、ack | 二重送信、古いETA |
| DLQ退避 | error、attempts、payloadRef | 復旧手順、荷主への個別連絡 |
この表をClaude Codeへ渡すと、実装前のレビュー観点が出ます。例えば「idempotencyKeyは何から作るか」「sequenceが古いイベントは捨てるか」「retryCountが何回を超えたらDLQへ送るか」「DLQを誰が何分おきに見るか」です。ここを言語化してからコードに入ると、初心者でも次の作業が見えます。
Claude Codeに任せる範囲と人が見る範囲
Claude Codeに任せる範囲は、Pub/Subトピック名の案、イベント項目の抜け漏れ、再送条件、DLQ後の確認表、テストイベントの作成です。配車表CSV、通知テンプレート、既存の遅延メール、障害時メモを読ませ、「この項目なら二重通知にならないか」を見ます。
人が見る範囲は、荷主への約束、個人情報、料金や補償、遅延理由の表現、謝罪文、電話連絡の要否です。Claude Codeが「この場合は自動通知でよい」と書いても、荷主との契約や現場事情は人が止めます。特に事故、天候、倉庫都合、ドライバー体調などは、文章の出し方ひとつで信頼が落ちます。
Pub/Subのexactly-once deliveryは名前だけ見ると安心に見えますが、外部へのメールやLINE送信まで一回にしてくれる魔法ではありません。公式ドキュメント上でも対象や条件を確認する必要があります。物流の通知では、アプリ側で「同じidempotency keyなら外へ送らない」という門番を持つほうが現実に合います。
3つのUse case
Use case 1: 遅延通知イベントの種類と送信条件を整理する
- 入力: 配車表CSV、遅延理由の選択肢、荷主向けメール文、LINEテンプレート、管理画面の通知履歴。
- 出力: shipment.delayed、shipment.eta_updated、shipment.deliveredなどのイベント表と、外部通知を送る条件。
- 人の確認: 遅延理由が荷主に見せてよい表現か、電話が先の案件ではないか、補償や契約条件が混ざっていないかを見る。
このUse caseでは、Claude Codeに「イベントを増やす」より「通知を送る条件」を書かせます。同じ遅延でも、ETAが5分だけ後ろにずれたケース、次回更新時刻だけ変わったケース、荷主の納品枠を超えるケースでは扱いが違います。
Use case 2: 再送と二重通知をidempotency keyで止める
- 入力: shipmentId、status、eta、channel、templateId、Pub/Sub messageId、既存の通知履歴。
- 出力: idempotency keyの作り方、重複時の処理、送信前チェック、監査ログの項目。
- 人の確認: 同じ荷物でも、見込み時刻が変わったら新しい通知として扱うか、前回通知の訂正として扱うかを決める。
idempotency keyは、同じ処理かどうかを見分ける合言葉です。例えば shipmentId、status、eta、channel をつなげて作ります。同じkeyがすでに送信済みなら、Pub/Subから再配信されても荷主へは送らず、ログだけ残します。
Use case 3: DLQと人の確認フローを作る
- 入力: retryCount、最後のエラー、通知本文、荷主ID、便番号、次回更新時刻、担当者。
- 出力: DLQに入れる条件、CSが見る確認表、再処理ボタンの条件、荷主への手動連絡文。
- 人の確認: 何度も失敗している通知を自動で再送し続けないか、担当者が見落とす場所に隔離していないかを見る。
DLQはDead Letter Queueの略で、処理に失敗し続けたメッセージを逃がす場所です。物流では「逃がしたから終わり」ではなく、荷主に連絡が届いていない可能性を示す赤信号として扱います。DLQの件数、最古の滞留時間、対象荷主、便番号をダッシュボードで見ます。
コピペで使えるプロンプト
あなたは物流会社のPub/Sub通知設計レビュー担当です。
目的は、遅延通知の二重送信、古いETA通知、DLQ放置を防ぐことです。
対象業務:
- 配車表のETA変更
- 荷主向けメール/LINE通知
- 管理画面の通知履歴
- DLQ後のCS確認
入力として渡すもの:
- 配車表CSVの列名
- 遅延理由の選択肢
- 通知テンプレート
- Pub/Subトピック/サブスクリプション案
- retry policy案
- DLQ topic案
出してほしいもの:
1. イベント名とpayload項目の表
2. idempotency keyの作り方
3. 再送してよい失敗と、人へ渡す失敗の分類
4. DLQに入った後の確認表
5. 本番前テストイベント10個
制約:
- 顧客名、電話番号、ドライバー個人情報をpayloadに入れすぎない
- ETAが古いイベントは外部通知しない
- 同じidempotency keyは外部通知しない
- 料金、補償、謝罪文は人が確認する
- 最後に、初心者が今日見るべき設定を3つに絞る
動く確認コード
物流会社のPub/Sub設計では、設定画面を見る前に小さな検査コードを走らせると、二重通知や古いETAに気づけます。次のコードは依存なしで動きます。わざと問題のあるイベントを入れているので、最初の実行ではエラー表が出ます。
// verify-logistics-pubsub.mjs
// No dependencies. Run with: node verify-logistics-pubsub.mjs
const events = [
{
shipmentId: "S-1001",
sequence: 12,
status: "delayed",
previousEta: "2026-07-19T16:30:00+09:00",
eta: "2026-07-19T17:10:00+09:00",
idempotencyKey: "S-1001:delayed:2026-07-19T17:10:00+09:00",
channel: "line",
retryCount: 0,
dlqTopic: "delay-notice-dlq",
reviewer: "cs-lead"
},
{
shipmentId: "S-1001",
sequence: 12,
status: "delayed",
previousEta: "2026-07-19T16:30:00+09:00",
eta: "2026-07-19T17:10:00+09:00",
idempotencyKey: "S-1001:delayed:2026-07-19T17:10:00+09:00",
channel: "line",
retryCount: 1,
dlqTopic: "delay-notice-dlq",
reviewer: "cs-lead"
},
{
shipmentId: "S-1002",
sequence: 5,
status: "delayed",
previousEta: "2026-07-19T18:20:00+09:00",
eta: "2026-07-19T18:00:00+09:00",
idempotencyKey: "S-1002:delayed:2026-07-19T18:00:00+09:00",
channel: "email",
retryCount: 4,
dlqTopic: "",
reviewer: ""
}
];
const seen = new Set();
const problems = [];
for (const event of events) {
if (seen.has(event.idempotencyKey)) {
problems.push({
shipmentId: event.shipmentId,
reason: "duplicate idempotency key",
fix: "publish the retry, but skip customer notification"
});
}
seen.add(event.idempotencyKey);
if (new Date(event.eta) <= new Date(event.previousEta)) {
problems.push({
shipmentId: event.shipmentId,
reason: "ETA did not move later",
fix: "do not send a delay notice; send to human review"
});
}
if (event.retryCount >= 3 && !event.dlqTopic) {
problems.push({
shipmentId: event.shipmentId,
reason: "retry limit reached without DLQ",
fix: "route to delay-notice-dlq and alert the CS lead"
});
}
if (!event.reviewer) {
problems.push({
shipmentId: event.shipmentId,
reason: "missing reviewer",
fix: "require a dispatcher or CS lead before customer send"
});
}
}
if (problems.length > 0) {
console.table(problems);
process.exitCode = 1;
} else {
console.log("Pub/Sub delay notification checklist passed.");
}
このコードで見ているのは4点です。idempotency keyが重複していないか、ETAが前回より遅くなっているか、再送回数が上限に近い時にDLQがあるか、担当者が入っているかです。現場では、この結果をそのままCIに入れるより、まず配車担当とCSが読む確認表にします。
Pitfall: よくある落とし穴
物流会社の通知で一番こわい落とし穴は、Pub/Subの再送を「もう一度送ってくれる便利な機能」とだけ見ることです。原因は、配信の再試行と、荷主への外部通知を同じものとして扱う点です。直し方は、Pub/Subから再配信されても、外部通知の手前でidempotency keyを見て止めることです。
二つ目は、ordering keyを入れたから古い通知が出ないと思い込むことです。順序制御は助けになりますが、どの単位で並べるかを間違えると、別の荷物まで詰まります。荷主単位で広く並べるより、shipmentIdや便番号に近い単位で考えます。さらに、古いsequenceは送信前に捨てる検査を入れます。
三つ目は、DLQを運用画面から遠い場所に置くことです。原因は、DLQを開発者だけが見る障害ログとして扱うことです。直し方は、DLQ件数、最古の滞留時間、荷主名の参照キー、便番号、担当者をCSの朝会チェックに入れることです。届いていない遅延通知は、問い合わせやクレームに直結します。
四つ目は、通知本文のClaude Codeへの丸投げです。遅延理由、謝罪、補償、到着見込みは、契約や荷主との関係で言葉が変わります。Claude Codeには文面の候補と確認観点を出させ、人が最後に送信可否を決めます。
よくある質問
Q. Pub/Subのexactly-once deliveryを使えば二重通知は消えますか。
A. それだけでは足りません。Pub/Sub側の配信確認と、メールやLINEなど外部送信の一回性は別です。通知サービス側でidempotency keyを保存し、同じkeyなら送らない処理を入れます。
Q. DLQに入ったメッセージはあとでまとめて再処理すればよいですか。
A. 物流の遅延通知では、時間が過ぎた通知をまとめて送ると逆効果です。再処理前にETA、納品状態、荷主への手動連絡済みかを人が見ます。
Q. Pub/Sub messageIdをidempotency keyにしてよいですか。
A. 業務上の重複を止めたいなら、shipmentId、status、eta、channel、templateIdなど、荷主通知の意味に近い項目で作るほうが扱いやすいです。messageIdだけだと、同じ遅延を別メッセージとして発行した時に止まりません。
Q. Claude Codeにはどこまで渡してよいですか。
A. 列名、マスク済みサンプル、通知テンプレート、Pub/Sub設定案、障害メモまでは渡しやすいです。荷主名、電話番号、ドライバー個人情報、契約条件、補償の話はマスクし、人が確認します。
研修・相談につなげるなら何を見るか
物流会社のPub/Sub記事から問い合わせへ進めるなら、PVだけを見ません。見る数字は、遅延連絡のやり直し回数、二重通知件数、DLQ滞留時間、荷主からの「どれが正しいのか」という電話件数、CSの確認時間です。ここが減るなら、通知設計の研修や相談に進む理由がはっきりします。
自社の配車表、通知テンプレート、Pub/Sub設定、DLQ確認表までまとめて見直したい場合は、ClaudeCodeLabの研修・相談で相談できます。まずはこの記事の確認コードを手元で動かし、二重通知になりそうなイベントを1つ書き出してください。
実際に試した結果
この記事では、Google Cloud公式ドキュメントでPub/Sub、subscription、retry policy、dead-letter topic、exactly-once delivery、ordering messagesの説明を確認しました。さらに、slug、frontmatter、内部リンク、外部リンク、CTA、コードブロック、10言語ファイルの有無、記事キューの削除対象を確認しています。今日まず見る1手は、配車表CSVから shipmentId、status、eta、channel を抜き出し、idempotency keyの案を1行で書くことです。
次に読む記事
イベント駆動アーキテクチャとは?pub/sub・Saga・冪等性を動くコードで
「いい感じに疎結合で」で組むと障害時に追えない。イベントとコマンドの違い、pub/sub、結果整合性、Sagaを動くNode.jsコードで整理した設計メモ。
WebSocketかSSEかポーリングか:リアルタイム機能の設計判断と落とし穴
リアルタイム機能の選び方を実務目線で。WebSocket vs SSE vs ポーリング、プレゼンス、再接続とハートビート、複数サーバーのpub/scaleまで僕の事故込みで解説。
物流会社の遅延連絡をClaude Codeで整える: 荷主に伝える順番と証跡
物流会社の遅延連絡を、荷主への説明順、証跡、再発防止、確認コードまで整える手順です。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。