アスクルの こたにん (@Kotanin0) です。
- Kotlin で AWS SDK を利用するには、今現在はJavaのものを使う必要がある
- AWS SDK for Java 2.x の非同期プログラミングはブロッキングされる
- AWS SDK for Java でノンブロッキングを実現する
- まとめ
Kotlin で AWS SDK を利用するには、今現在はJavaのものを使う必要がある
KotlinでAWSのいろいろを操作する際に、AWSが提供しているSDKを利用すると便利です。
が、2022年3月現在、Kotlin向けのAWS SDKはプレビュー版で、正式リリースがされていません。
AWS SDK for Kotlin (デベロッパープレビュー)
そのため、今現在は AWS SDK for Java を使う必要があります。
AWS SDK for Java
AWS SDK for Java 2.x の非同期プログラミングはブロッキングされる
AWS SDK for Java の最新メジャーバージョンの2.系には、非同期プログラミング向けの機能が搭載されています。
Asynchronous programming - AWS SDK for Java 2.x Developer guide
だがこれは、Kotlin CoroutinesやSpring WebFluxのようなリアクティブプログラミングと組み合わせるには注意が必要です。
suspend fun hasObject(): Boolean = coroutineScope { val request = ListObjectsV2Request.builder() .bucket(bucket) .build() val result = s3AsyncClient.listObjectsV2(request).join() // <- blocking :( result.contents().size > 0 }
上のようなコードがあったときに、.join()
がブロッキングコードになってしまうのです。
AWS SDK for Java でノンブロッキングを実現する
s3AsyncClient
に用意されているメソッドたちは、基本的にCompletableFuture<T>
を返すつくりになっています。
Interface S3AsyncClient
なので、CompletableFuture<T>
をsuspend fun
に置き換えてあげるとよいです。
Kotlin KEEP に、コールバック関数と中断関数の変換に関するとてもわかりやすいサンプルが載っています。
(droidkaigi にも「コールバックを使った既存のAPIを中断関数に置き換える」例がありますので合わせてご覧ください)
suspend fun <T> CompletableFuture<T>.await(): T = suspendCoroutine<T> { cont: Continuation<T> -> whenComplete { result, exception -> if (exception == null) // the future has been completed normally cont.resume(result) else // the future has completed with an exception cont.resumeWithException(exception) } }
JavaのCompletableFuture.whenComplete
コールバックで、KotlinのContinuation.resume/resumeWithException
を返すという処理です。
これによって、Javaのコールバック関数を、Kotlin Coroutines上で中断関数として扱えます。
suspend fun hasObject(): Boolean = coroutineScope { val request = ListObjectsV2Request.builder() .bucket(bucket) .build() // val result = s3AsyncClient.listObjectsV2(request).join() val result = s3AsyncClient.listObjectsV2(request).await() // non-blocking :) result.contents().size > 0 }
これでノンブロッキング。
ブロッキングコードの検出については BlockHound で行いました。
BlockHoundは改めて記事にできたらしようかな。
まとめ
Kotlin Coroutines を使う場合は、非同期プログラミングの旨味が失われてしまわないように、ブロッキングコードの取り扱いには十分気をつけましょう。
AWS SDK for Kotlin 早くリリースされないかなぁ。。。