本文へ移動
技術を、自社の仕事に。
判断と実行を助けるメディア

記事を検索

DB更新と出荷依頼を同時に確定 Spanner queues

目次 · 5項目

注文を確定したら、倉庫のシステムへ出荷依頼を送る。データベースの更新は成功したのに、メッセージの送信だけ失敗すると、注文は「確定」なのに出荷されません。逆に、メッセージを送った後でデータベースの更新が取り消されると、存在しない注文の出荷が始まります。データベースとメッセージキューを別々に書く「二重書き込み」で起きる、業務システムの典型的な不整合です。

Google Cloudは2026年10月2日の公式ブログで、Spannerにトランザクション内でメッセージを扱える「Spanner queues」の一般提供を始めたと発表しました。ブログはAIエージェントの用途を中心に説明していますが、注文処理や在庫のワークフローにも使えるとしています。ブログとSpanner APIの仕様を読み、二重書き込みの問題にどう効くかを整理します。

二重書き込みで起きること

ブログは、状態の更新とメッセージの送信を別のシステムで行う場合の失敗を2つ挙げています。

  • データベースの更新が成功し、メッセージの送信が失敗する:決めたのに実行されない
  • メッセージの送信が成功し、データベースの更新が取り消される:無効な状態にもとづいて実行される

これを避けるために、開発者は「アウトボックス」(送るべきメッセージをいったん同じDBの表に書き、別の処理が拾って送る仕組み)や、重複して処理しないための仕組み、ずれを直す処理を自前で作ってきた、とブログは説明しています。

Spanner queuesでは、メッセージの作成が同じトランザクション内の書き込みの1つになります。状態の更新と次に実行すべき処理が、両方とも確定するか、両方とも取り消されるかのどちらかになります。

二重書き込みとSpanner queuesの違いを示した図。左は、データベースの更新とキューへの送信が別々に確定するため、片方だけ成功する不整合が起きうる構成。右は、注文の更新とキューへのメッセージの挿入が1つのトランザクションで同時に確定する構成。図の内容はGoogle Cloudの公式ブログの説明にもとづく

SQLでの書き方

キューは、SpannerのGoogleSQLで定義・操作する表のような構造です。ブログにある返金の承認の例を引用します(SQLのコメントは編集部が要約)。

CREATE QUEUE OrderAgentTasks (
  OrderId STRING(64) NOT NULL,
  TaskId STRING(64) NOT NULL,
  TaskType STRING(64) NOT NULL,
  Payload JSON NOT NULL
) PRIMARY KEY (OrderId, TaskId, TaskType), INTERLEAVE IN Orders;

-- 同じ読み書きトランザクションの中で
UPDATE Orders
SET Status = 'REFUND_APPROVED',
    UpdatedAt = PENDING_COMMIT_TIMESTAMP()
WHERE OrderId = @orderId;

INSERT INTO OrderAgentTasks (OrderId, TaskId, TaskType, Payload)
VALUES (@orderId, @taskId, 'EXECUTE_REFUND',
  JSON '{"action": "execute_refund", "amount": 49.99}');

ブログは、この形なら「注文の状態が承認済みに変わったときに限り、返金のタスクが存在する」と説明しています。

ほかに、ブログは次の書き方を示しています。

  • 遅らせて配信する。 システム列の DeliverTime に時刻を入れると、その時刻まで受信側に見えません。例では72時間後に上長へのエスカレーションを予約しています
  • 予約を取り消す。 承認が先に来たら、状態の更新と同じトランザクションで DELETE し、予約したメッセージを消します
  • 受け取る。 処理する側は RECEIVE_<キュー名> という関数をストリーミングで読み、メッセージを一定時間借り受けます(リース)。時間がかかる処理は RENEWLEASE_<キュー名> で延長します
  • 完了を記録する。 結果の書き込みとメッセージの DELETE を1つのトランザクションで行い、ASSERT_ROWS_MODIFIED 1 を付けます。リースが切れて別の処理がすでに片付けていた場合は、ここでエラーになり、古い処理が新しい状態を上書きするのを防げます

「ちょうど1回」は自分で仕上げる

ブログの表現は「少なくとも1回の配信(at-least-once)と、高々1回の完了記録(at-most-once ACK)を保証し、これによってちょうど1回の処理を実現できる」です。同じメッセージを2回受け取ることはありうる前提です。外部のAPIを呼ぶ場合、ブログは TaskId を相手側の冪等キー(同じ依頼を2回受けても1回分として扱うための値)に渡す例を示しています。決済や出荷のように二重実行が問題になる処理では、この設計が欠かせません。

使う前に確かめること

変更ストリームとの使い分け

Spannerには、データの変更を取り出す「変更ストリーム(change streams)」もあります。ブログは、変更ストリームは分析や保存先への継続的な変更データの取り込み向け、キューはリースや予約配信、トランザクション内での完了記録を伴うタスクの実行向け、と分けています。

クライアントライブラリの対応

Spanner API v1の仕様(Discoveryドキュメント、revision 20260909)では、書き込みの単位である Mutation に、キューへの send と ack が入っています。send は deliverTime を指定でき、ack は ignoreNotFound で、存在しないメッセージの完了記録を成功扱いにできます。

各言語の公式ライブラリのCHANGELOGには、次の版で「Send and Ack」の対応が書かれています。

  • Go:1.87.0(2025年12月10日)、1.88.0(2026年2月11日)
  • Java:6.109.0(2026年2月2日)
  • Python:3.60.0(2025年12月10日)

Node.jsは、GitHubのnodejs-spannerリポジトリのCHANGELOGが8.6.0(2026年1月28日)で止まっており、該当する記載はありません。一方、npmで公開されている @google-cloud/spanner 9.0.0(2026年9月18日公開)の型定義には、queueSend と queueAck(ignoreNotFound を指定できる)がありました(10月5日に確認)。

公式ブログに書かれていないこと

対象のエディション、料金、キューごとの上限、Spanner Omni(自社環境で動かす版)で使えるかどうかは、ブログに記載がありません。Google Cloudのドキュメントは編集部の環境から開けず、確認できていません。採用を検討するときは、ドキュメントで確かめてください。

既存のシステムで考えること(編集部の整理)

すでにPostgreSQLなどで業務システムを動かしているなら、同じDBにアウトボックス表を置く方法でも二重書き込みは避けられます。キューのためだけにSpannerへ移る理由にはなりにくく、DBを増やす前に1つのDBでどこまで持つかはPostgres1本で持たせる判断で整理しています。

Spanner queuesが効くのは、すでにSpannerを使っている、またはこれから使う構成で、外部のキューとアウトボックスの中継処理をなくしたい場合です。Spannerを自社環境で動かす選択肢はSpanner Omniの記事で扱っています。

2026年10月3日に、Google Cloud公式ブログ「Announcing Spanner queues: Transactional messaging for agentic workloads and beyond」(2026年10月2日)、Spanner API v1のDiscoveryドキュメント(revision 20260909)、googleapisのgoogle-cloud-go(spanner)・java-spanner・python-spanner・nodejs-spannerのCHANGELOGを直接開いて照合しました。10月5日にnpmの @google-cloud/spanner 9.0.0の型定義も確認しました。Spannerのドキュメント(docs.cloud.google.com)は編集部の環境から開けず、エディション・料金・上限は確認していません。実際のSpannerインスタンスやエミュレーターでの動作は検証していません。

業務システムのデータ設計や、DBと外部サービスの連携の見直しは、開発・AI・自動化のご相談からお問い合わせください。

Sources

この記事を共有XFacebook
鈴木 翔

技術の可能性に魅了され、学生時代からプログラミングとデジタルアートの分野に深い関心を持つ

この記事のテーマを、自社の次の一歩へ

自社での進め方を、具体的に。

つくりたい仕組み、既存システム、運用の条件を整理し、実現に向けた次の一歩を考えます。

  • 実現したい仕組み
  • 既存環境との接続
  • 運用の条件
開発・運用の構想を相談する

構想段階からご相談いただけます。この記事の情報を相談フォームに引き継ぎます。

最新記事をメールで受け取る