同期連携で実際に気を配ること
一言でいうと
同期RESTの連携の難しさは、呼び出しではなく待つことにあります。タイムアウトを設定しないと、相手システムの障害が、そのままこちらのシステムの障害になります。
同期連携の本当の危険が「待つこと」なのはなぜか
RESTで相手システムを呼び出すのは簡単です。難しいのは、相手が遅いときです。
こちらの画面が相手のAPIを同期で呼んでいて、相手が30秒かかるとします。
- こちらのWASのスレッドが30秒間拘束されます
- ユーザーは画面の前で待ちます。たいてい、リロードを押します
- リロードは、リクエストをもう1つ作ります。前のリクエストは生きています
- スレッドが急速に枯渇します。相手システムの障害が、こちらのシステムの障害になります
そのため、同期連携には必ずタイムアウトが必要です。2種類あります。
연결 타임아웃(connect) : 상대와 TCP 연결이 맺어질 때까지 → 짧게 (1~3초)
응답 타임아웃(read) : 응답을 다 받을 때까지 → 업무에 따라 (5~30초)
このコードブロックの韓国語は、接続タイムアウト(connect)は、相手とTCP接続が確立するまでの時間なので短く(1–3秒)、応答タイムアウト(read)は、応答をすべて受け取るまでの時間なので業務に応じて(5–30秒)設定する、という意味です。
接続タイムアウトを短く設定することが重要です。相手のサーバーが死んでいれば、接続はすぐに失敗しなければなりません。これを30秒にしておくと、相手が死んでいる間、こちらのスレッドが30秒ずつ拘束されます。
そして、タイムアウトだけでは足りません。相手がずっと遅ければ、こちらもずっと拘束されます。そのときに必要なのがサーキットブレーカーです。失敗率がしきい値を超えると、一定時間、まったく呼び出さずに即座に失敗させます。「すばやく失敗すること」が「遅い成功を待つこと」よりよい状況があります。
タイムアウトは「応答がない」という意味ではありません
ここが最も重要なポイントです。
タイムアウトが起きたとき、相手がリクエストを受け取れなかったのか、 処理はしたのに応答だけ届かなかったのかを、こちらは区別できません。
注文の送信でタイムアウトが起きました。再送するべきでしょうか。
- 相手が受け取れていなければ、再送する必要があります
- 相手が処理していたなら、再送は重複注文です
この問題は、再試行では解けません。冪等性で解きます。送信側が毎回のリクエストに一意のキー(電文番号、Idempotency-Key)を付け、受信側が同じキーを2回受け取ったら、処理せずに最初の応答をそのまま返します。そうすれば、再送が安全になります。これは、後のモジュールのラボで扱います。
リクエスト前の検証: 出ていく前に止める
相手に送る前に、こちらが先に検証すべきことがあります。
- 必須値: 定義書の必須項目がすべてあるか
- 長さ: バイト基準で超過していないか
- 型/形式: 日付の形式、数値フィールドに文字が入っていないか
- コード値: 定義書に明記されたコード一覧の中にあるか
これをしないと、相手システムのエラー応答で知ることになります。そうすると
- 往復の時間が無駄になり、
- 相手システムのログにこちらのエラーが溜まり(連携担当者間の感情的な消耗)、
- 大量バッチなら、数千件のエラーが一度に噴き出します
「悪いデータはこちら側で止める」が、連携開発の基本的なマナーです。
連携ログは別に残す
アプリケーションログに混ぜておくと、あとで見つけられません。連携専用のログを作り、1行に1回の呼び出しを残します。フィールドは、最低でもこのくらいです。
2026-08-19T14:03:22.145+0900|IF-ORD-001|ORDER-SYS|PARTNER-API|0000|182|a1b2c3d4
시각 인터페이스ID 송신 수신 응답코드 소요ms 추적ID
このコードブロックの2行目の韓国語は、各フィールドの名前を順に、時刻、インターフェースID、送信、受信、応答コード、所要ms、追跡IDと示しています。
- 追跡ID(trace_id)が特に重要です。相手システムのログと突き合わせるときに、これ1つで探します。リクエストヘッダーで一緒に送り、相手にも残してもらうように、定義書に書いておきます。
- 所要時間を残せば、「最近遅くなった」という話に根拠を示せます。
- レスポンスコードを残せば、エラーの分布を集計できます。
そして、個人情報をログに残しません。住民登録番号、口座番号、カード番号は、マスキングするか、まったく残しません。連携ログは長く保管されるので、リスクが大きいです。
大量処理は同期で行わない
「注文10万件を相手に送信」のような要件に、同期RESTを使ってはいけません。1件に100msしかかからなくても、10万件なら約2.8時間です。その間に1回でも切れたら、どこまで進んだかわかりません。
代替案は3つです。
- ファイルバッチ: 一度にまとめて送り、結果をファイルで受け取ります
- キュー: 非同期で投げて、結果は別に通知します
- バルクAPI: 1リクエストにN件(通常100–1000)を入れ、件ごとの結果を受け取ります
3つ目を使うときに必ず定義すべきこと: 部分的な失敗をどう処理するか。100件のうち3件が失敗したら、全体をロールバックするのか、97件は処理して3件だけを返すのか。定義書になければ、双方が違う形で実装します。そして、この違いは、「件数が合わない」という形で、数日後に発見されます。
現場での姿
この失敗は、いつも同じ形で来ます。相手のAPIが遅くなり、こちらの画面が止まり、ユーザーがリロードを押し、そのリロードがリクエストをもう1つ作ります。前のリクエストはまだ生きているので、スレッドは2倍拘束されます。数分後に、こちらのWASのスレッドが枯渇し、相手とまったく関係のない画面まで、すべて止まります。
このとき、モニタリングでは、こちらのシステムのCPUもメモリも正常に見えます。スレッドが仕事をしているのではなく、待っているだけだからです。そのため、原因を相手ではなくこちら側で探して、時間を浪費します。
連携ログを別に残す必要がある理由が、これです。アプリケーションログに混ぜておくと、「相手がいつから遅くなったのか」を取り出すのに時間がかかります。インターフェースID・レスポンスコード・所要時間を固定の形式で1行ずつ残しておけば、その答えは1分で出ます。