Hitachi

Hitachi Microservices Platform - Paxos Commit Transaction Orchestrator ユーザーズガイド


2.2.8 通信によるトランザクションブランチの作成(REST通信-クライアント)

REST通信によるトランザクションブランチを作成するクライアントの開発方法について説明します。

Spring Framework のRestTemplateを使用してトランザクションブランチを作成します。REST通信によるトランザクションブランチの作成は、次のアプリケーションで実装してください。

クライアントでは、HMP-PCTOのインタセプタを登録してトランザクションを伝搬する必要があります。また、トランザクションブランチを作成することで、先行プリペア機能を使用できます。

インタセプタの登録方法と、先行プリペア機能の使用方法を次に示します。

〈この項の構成〉

(1) Spring Framework のRestTemplateを使用したインタセプタの登録

TxPropagationRestTemplateInterceptorクラスをorg.springframework.web.client.RestTemplateクラスのsetInterceptors()メソッド、またはorg.springframework.boot.web.client.RestTemplateBuilderクラスのinterceptors()メソッドで登録して使用します。

(a) ライブラリの組み込み

TxPropagationRestTemplateInterceptorクラスを登録するには、次のライブラリをアプリケーションに組み込む必要があります。

  • hmppcto-propagation-rest-template

  • hmppcto-common

Gradleで組み込む記載例を次に示します。

dependencies {
    implementation 'jp.co.Hitachi.soft.hmppcto:hmppcto-propagation-rest-template:<V.R.S>'
    implementation 'jp.co.Hitachi.soft.hmppcto:hmppcto-common:<V.R.S>'
}
注※

V.R.Sは使用するHMP-PCTOのバージョンに合わせて読み替えてください。

(b) 宛先のホスト部分の形式

トランザクションの伝搬時、HTTP通信に指定する宛先のホスト部分は、宛先のServiceを示すドメイン名で指定してください。

スケーリング対応機能を有効にした場合は、次の形式で指定する必要があります。

Serviceを示すドメイン名の指定形式を次に示します。

  • <Service名>

  • <Service名>.<Namespace名>

  • <Service名>.<Namespace名>.svc

上記以外の形式で宛先を指定した場合は、HMP-PCTOの機能は正しく動作しません。

以降に、宛先のServiceへのHTTP通信に指定するドメイン名の例を示します。

RequestEntity<MyRequest> request = RequestEntity    // エンティティ作成
     .post("https://my-svc.my-namespace.svc:8080/{foo}", "bar")          // 宛先のServiceを示すドメイン名で指定
     .body(body);

この例では、宛先のServiceのServiceを示すドメイン名を"my-svc.my-namespace.svc"(「<Service名>.<Namespace名>.svc」形式)としています。

(c) コーディング例

org.springframework.web.client.RestTemplateクラスのsetInterceptors()メソッドを使用して登録する例を説明します。アプリケーションが使用するほかのインタセプタとの登録順番に制約はありません。

TxPropagationRestTemplateInterceptorクラスのインスタンスは@AutowiredアノテーションでDIして取得してください。DIしたインスタンスを使用するメソッドのアクセス制御修飾子は、private以外にしてください。privateとした場合は、HMP-PCTOの機能は正しく動作しません。

@Autowired
TxPropagationRestTemplateInterceptor txIc;
 
RestTemplate restTemplate = new RestTemplate();                 // RestTemplateのインスタンス作成
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();   // インタセプタのリストを作成
interceptors.add(txIc);                                         // HMP-PCTOのインタセプタをリストに追加
restTemplate.setInterceptors(interceptors);                     // RestTemplateにインタセプタを登録

(d) エラーハンドリング

RestTemplateを利用した通信時に動作するTxPropagationRestTemplateInterceptorクラスの前提処理で例外が発生したとき、RestClientExceptionが送出されます。必要に応じて例外をcatchして後処理をしてください。

この場合、例外のCausedには次の例外の情報が出力されます。

  • jp.co.Hitachi.soft.hmppcto.lb.exception.ServiceNotFoundException

  • jp.co.Hitachi.soft.hmppcto.lb.exception.PodNotFoundException

RestTemplateを使用した通信で例外が発生した場合に、例外のCausedに次のようにHMP-PCTOのTxPropagationRestTemplateInterceptorクラスで例外が発生したことを示すスタックトレースが出力されます。これは、例外が発生した直接の原因を示すものではありません。直接の原因は、例外のCausedの前に出力された内容を参照してください。

Caused by: java.net.SocketException: Unexpected end of file from server
:
at org.springframework.http.client.AbstractClientHttpResponse.getStatusCode(AbstractClientHttpResponse.java:33)
at jp.co.Hitachi.soft.hmppcto.filter.propagation.TxPropagationRestTemplateInterceptor.intercept(TxPropagationRestTemplateInterceptor.java:93)
:

(2) 先行プリペア機能の使用

先行プリペア機能を使用するには、トランザクションを伝搬する際にクライアントアプリケーションでHMP-PCTOが提供するインタフェースを使用して、HTTPヘッダを追加します。

(a) ライブラリの組み込み

先行プリペア機能を使用する場合に組み込むライブラリは、トランザクションの伝搬に使用するライブラリと同じです。ライブラリについては、「(a) ライブラリの組み込み」を参照してください。

(b) コーディング例

先行プリペア機能を使用する際に追加するHTTPヘッダ名と値は、XidHeadersインタフェースで提供します。ヘッダ名と値の詳細については、「8.2.4 XidHeadersインタフェース(SQL-Participant限定)」を参照してください。トランザクションの伝搬に使用するクライアントごとに追加する例を次に示します。

■ Spring FrameworkのRestTemplateを使用する場合

RequestEntity<MyRequest> request = RequestEntity               // RequestEntity作成
     .post("https://example.com/{foo}", "bar")
     .header(XidHeaders.IS_LAST_CALL, XidHeaders.TRUE)         // 先行プリペアヘッダ追加
     .body(body);

(c) エラーハンドリング

先行プリペア機能の使用によって、アプリケーションでエラーハンドリングが必要なエラーが発生することはありません。

(3) 注意事項

先行プリペア実行後に、再度同じサービスを呼び出してもSQLは実行できません。先行プリペア実行後にSQLを実行するためにJDBC Proxy Driverのメソッドを実行した場合は、PctoPrePreparedException例外を送出して、SQLを実行しないで無視します。トランザクションがコミットするかロールバックするかには影響しません。アプリケーションでPctoPrePreparedException例外をキャッチしてロールバックするかどうかを判断してください。