S-JIS[2023-10-06/2023-10-24]
TsurugiのTsubakuro(Java通信ライブラリー)のFutureResponseのメモ。
Tsubakuroは非同期APIである。
つまり、TsubakuroでTsurugiサーバーと通信する処理を呼び出すと、FutureResponse(Java標準のFuture相当)が(即座に)返ってくる。
必要な値はFutureResponseからgetする。(通信に時間がかかる場合は、このメソッド内で待つ)
また、FutureResponseはクローズする必要がある。(FutureResponseはFutureと似ているが、AutoCloseableである点が異なる)
(FutureResponseからのgetに成功した場合はクローズしなくてもいいようだが、念のため常にクローズすべきだろう)
import java.util.concurrent.TimeUnit; import com.tsurugidb.tsubakuro.util.FutureResponse;
try (FutureResponse<Transaction> future = sqlClient.createTransaction(option)) { try (Transaction transaction = future.get(3, TimeUnit.SECONDS)) { 〜 } }
FutureResponseからgetメソッドで値(この例ではTransactionインスタンス)を取得する。
getメソッドの引数は通信のタイムアウト時間。
ただ、getを使う方法だと、FutureResponse自身のtry文とgetした値のtry文が二重になってしまうので、コーディングしにくい。(try文を入れないと、例外発生時にクローズが漏れる危険性がある)
そのため、getメソッドの代わりに使えるawaitメソッドが用意されている。
awaitメソッドはgetした値を返し、(getが成功しても失敗しても)常にFutureResponseのクローズを行う。
try (Transaction transaction = sqlClient.createTransaction(option).await(3, TimeUnit.SECONDS)) { 〜 }
ただし、Tsubakuroを使ったコーディングではawaitメソッドは便利だが、常に応答を待つことになるので、効率が悪い場合がある。
例えばinsert文の実行をawaitで行うと、大量のinsertを行う場合でも1件実行する度に完了を待つことになる。
insertを実行してFutureResponseを保持し、数十件insertした後でまとめてFutureResponseからgetした方がスループットは良い。(ただし、まとめて応答を待つにも上限があるので、ある程度の件数で実施する必要がある)
FutureResponseのgetメソッドやawaitメソッドには、タイムアウト時間を指定しないオーバーロードがある。
タイムアウト時間を指定しないと無限に待つ。
例えばTsurugiサーバーがクラッシュすると、TCP接続ならソケット通信の切断を検知して(検知できれば)getやawaitでエラーになるが、IPC接続ではサーバーがクラッシュしたことを検知できないので、無限に待つことになる。(Tsurugi 1.0.0の場合)
また、Tsubakuroのリソースには、クローズ時にTsurugiサーバーに終了メッセージを送信するものもある。[2023-10-24]
そのため、FutureResponseではクローズ処理用のタイムアウト時間を指定できるようになっている。
import java.util.concurrent.TimeUnit; import com.tsurugidb.tsubakuro.util.Timeout; import com.tsurugidb.tsubakuro.util.Timeout.Policy;
future.setCloseTimeout(new Timeout(10, TimeUnit.SECONDS, Policy.ERROR));
Policyは、タイムアウト時間を過ぎたときにどういう動作をするかを指定する。
Policy | 説明 |
---|---|
IGNORE |
何もしない(DEBUGレベルのログ出力のみ) |
WARN |
何もしない(WARNレベルのログ出力のみ) |
ERROR |
ResponseTimeoutExceptionをスローする。 |