堅牢なコルーチンアーキテクチャの設計
supervisorScope、リトライロジック、ハンドラーを組み合わせ、本番品質の並行処理を実現します。
「堅牢なコルーチンアーキテクチャの設計」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。
コルーチンをレジリエントにするもの
レジリエントなコルーチンアーキテクチャは、失敗を適切に処理します。失敗を分離し、一時的なエラーを再試行し、古くなった処理をキャンセルし、リソースを確実にクリーンアップします。
import kotlinx.coroutines.*
// Resilience pillars:
// 1. Failure isolation (SupervisorJob)
// 2. Retry with backoff (retry operator / loop)
// 3. Timeout guards (withTimeout)
// 4. Clean teardown (finally + NonCancellable)
// 5. Observability (CoroutineExceptionHandler)
fun main() = runBlocking { println("Design for failure from the start") }アプリレベルのスコープパターン
SupervisorJob + handler を備えた単一のアプリレベル CoroutineScope を作成します。各サービスに注入することで、すべてのサービスで同じライフサイクルを共有できます。
import kotlinx.coroutines.*
object AppCoroutineScope {
private val handler = CoroutineExceptionHandler { _, e ->
println("[AppScope] Uncaught: ${e.message}")
}
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default + handler)
fun cancel() = scope.cancel()
}指数バックオフによるリトライ
ネットワーク呼び出しを指数バックオフ付きのリトライループでラップし、一時的な失敗を適切に処理します。
import kotlinx.coroutines.*
suspend fun <T> retryWithBackoff(
times: Int = 3,
initialDelay: Long = 100,
block: suspend () -> T
): T {
var delay = initialDelay
repeat(times - 1) { attempt ->
try { return block() }
catch (e: Exception) {
if (e is CancellationException) throw e
println("Attempt ${attempt+1} failed, retrying in ${delay}ms")
delay(delay)
delay *= 2
}
}
return block()
}
fun main() = runBlocking {
var n = 0
val result = retryWithBackoff {
if (n++ < 2) throw RuntimeException("transient")
"success"
}
println(result)
}サーキットブレーカーパターン
サーキットブレーカーは、N 回失敗したサービスへの呼び出しを停止し、クールダウン後に再開します。これにより、連鎖的な障害を防ぎます。
import kotlinx.coroutines.*
class CircuitBreaker(val maxFailures: Int, val cooldownMs: Long) {
private var failures = 0
private var openUntil = 0L
suspend fun <T> call(block: suspend () -> T): T {
if (System.currentTimeMillis() < openUntil) throw RuntimeException("Circuit open")
return try {
val result = block()
failures = 0
result
} catch (e: Exception) {
if (e is CancellationException) throw e
if (++failures >= maxFailures) openUntil = System.currentTimeMillis() + cooldownMs
throw e
}
}
}すべての外部呼び出しにタイムアウトを設定する
外部 I/O は必ず withTimeout または withTimeoutOrNull でラップします。ハングした接続によってコルーチンが無期限にブロックされることがないようにしてください。
import kotlinx.coroutines.*
suspend fun fetchWithTimeout(url: String): String? = withTimeoutOrNull(3000) {
// ktor: client.get(url).body()
delay(100) // simulate
"response from $url"
}
fun main() = runBlocking {
val result = fetchWithTimeout("https://api.example.com")
println(result ?: "Timed out")
}機能ごとの構造化スコープ
機能または画面ごとに、独自の SupervisorJob を持つ別個の CoroutineScope を作成します。機能が破棄されたときにキャンセルしてください。
import kotlinx.coroutines.*
class FeatureController {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
fun start() {
scope.launch { /* load data */ }
scope.launch { /* subscribe to updates */ }
}
fun destroy() = scope.cancel() // cancels all feature coroutines
}use() によるリソースの安全性
AutoCloseable リソースには use { } を使用します。コルーチンのキャンセルと組み合わせると、コルーチンがキャンセルされた場合でもリソースが閉じられます。
import kotlinx.coroutines.*
class Connection : AutoCloseable {
override fun close() = println("Connection closed")
suspend fun fetch(): String { delay(100); return "data" }
}
fun main() = runBlocking {
val job = launch {
Connection().use { conn ->
println(conn.fetch())
} // close() called even on cancellation
}
delay(50)
job.cancelAndJoin()
}グレースフルシャットダウン
新しい処理の受け付けを停止し、実行中のコルーチンが完了するまで待機してからスコープをキャンセルする、グレースフルシャットダウンを実装します。
import kotlinx.coroutines.*
class WorkQueue {
private val scope = CoroutineScope(SupervisorJob())
private val jobs = mutableListOf<Job>()
fun submit(block: suspend () -> Unit) {
jobs += scope.launch { block() }
}
suspend fun shutdown() {
jobs.forEach { it.join() } // wait for all
scope.cancel() // then cancel scope
}
}
fun main() = runBlocking {
val q = WorkQueue()
repeat(3) { i -> q.submit { delay(50); println("Task $i done") } }
q.shutdown()
println("Queue shut down cleanly")
}可観測性:CoroutineName
デバッグのために CoroutineName でコルーチンに名前を付けます。名前はスタックトレースに表示され、例外ハンドラーで構造化ロギングに利用できます。
import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { ctx, e ->
println("[${ctx[CoroutineName]?.name}] Failed: ${e.message}")
}
CoroutineScope(SupervisorJob() + handler).apply {
launch(CoroutineName("UserLoader")) { throw RuntimeException("DB error") }
launch(CoroutineName("Analytics")) { delay(100); println("Analytics ok") }
delay(200); cancel()
}
}GlobalScope を避ける
本番環境では GlobalScope を決して使用しないでください。親、ライフサイクル管理、構造化されたキャンセルのないコルーチンを作成してしまいます。代わりに、スコープを持つ方法を使用してください。
import kotlinx.coroutines.*
// BAD — GlobalScope leaks coroutines:
// GlobalScope.launch { delay(Long.MAX_VALUE) }
// GOOD — scoped, cancellable:
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
scope.launch { delay(100); println("Scoped") }
fun main() = runBlocking { delay(200); scope.cancel() }レジリエンスのテスト
TestCoroutineScheduler と runTest を使用すると、実際の遅延なしにユニットテストで失敗、タイムアウト、リトライをシミュレートできます。
import kotlinx.coroutines.*
import kotlinx.coroutines.test.*
fun testRetry() = runTest {
var attempts = 0
val result = retryWithBackoff(3, 100) {
if (attempts++ < 2) throw RuntimeException("fail")
"ok"
}
println(result) // "ok"
}
// In test, virtual time advances instantly through delaysクイックチェック
長期間存続するレジリエントなコルーチンスコープの基盤となる組み合わせはどれですか。
振り返り
レジリエントなアーキテクチャでは、分離のための SupervisorJob、一時的なエラーのための retryWithBackoff、停止した I/O のための withTimeout、クリーンアップのための finally/NonCancellable、可観測性のための CoroutineExceptionHandler を組み合わせます。
よくある質問
「堅牢なコルーチンアーキテクチャの設計」レッスンは無料ですか?
はい。「堅牢なコルーチンアーキテクチャの設計」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。
「堅牢なコルーチンアーキテクチャの設計」で何を学びますか?
supervisorScope、リトライロジック、ハンドラーを組み合わせ、本番品質の並行処理を実現します。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Kotlin Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「堅牢なコルーチンアーキテクチャの設計」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このKotlin Academyレッスンでコードを書いて実行できますか?
はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- SupervisorJobとJob:失敗の分離
- CoroutineExceptionHandler:グローバルな未捕捉例外ハンドラー
- async/awaitによる例外の伝播
- 堅牢なコルーチンアーキテクチャの設計