Projetando arquiteturas resilientes de corrotinas
Combine supervisorScope, lógica de repetição e manipuladores para obter concorrência adequada a ambientes de produção.
Projetando arquiteturas resilientes de corrotinas é uma aula grátis de Kotlin Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Kotlin Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Kotlin Academy inclui 4 aulas no total.
O Que Torna as Corrotinas Resilientes
Arquiteturas de corrotinas resilientes lidam com falhas de forma adequada: isolam falhas, repetem operações após erros transitórios, cancelam trabalhos obsoletos e liberam recursos de maneira determinística.
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") }Padrão de Escopo no Nível da Aplicação
Crie um único CoroutineScope no nível da aplicação, com SupervisorJob + handler. Injete-o nos serviços para que todos compartilhem o mesmo ciclo de vida.
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()
}Repetição com Intervalo Exponencial
Envolva as chamadas de rede em um laço de repetição com intervalo exponencial para lidar adequadamente com falhas transitórias.
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)
}Padrão de Disjuntor
Um disjuntor para de chamar um serviço com falhas após N falhas e reabre depois de um período de espera — evitando falhas em cascata.
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
}
}
}Tempo Limite para Toda Chamada Externa
Sempre envolva operações externas de E/S com withTimeout ou withTimeoutOrNull. Nunca permita que uma conexão travada bloqueie uma corrotina indefinidamente.
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")
}Escopo Estruturado por Recurso
Crie um CoroutineScope separado para cada recurso ou tela, com seu próprio SupervisorJob. Cancele-o quando o recurso for destruído.
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
}Segurança de Recursos com use()
Use use { } para recursos AutoCloseable. Combine isso com o cancelamento da corrotina: os recursos serão fechados mesmo quando a corrotina for cancelada.
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()
}Desligamento Gracioso
Implemente um desligamento gracioso: pare de aceitar novos trabalhos, aguarde a conclusão das corrotinas em andamento e depois cancele o escopo.
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")
}Observabilidade: CoroutineName
Marque as corrotinas com CoroutineName para facilitar a depuração. Os nomes aparecem nos rastreamentos de pilha e podem ser usados nos manipuladores de exceções para registro estruturado.
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()
}
}Evite GlobalScope
Nunca use GlobalScope em produção. Ele cria corrotinas sem pai, sem gerenciamento do ciclo de vida e sem cancelamento estruturado. Use alternativas associadas a escopos.
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() }Testando a Resiliência
Use runTest com TestCoroutineScheduler para simular falhas, tempos limite e repetições em testes unitários sem atrasos reais.
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 delaysVerificação Rápida
Qual combinação forma a base de um escopo de corrotinas resiliente e de longa duração?
Recapitulação
Arquiteturas resilientes combinam SupervisorJob para isolamento, retryWithBackoff para erros transitórios, withTimeout para E/S travadas, finally/NonCancellable para limpeza e CoroutineExceptionHandler para observabilidade.
Perguntas Frequentes
A aula “Projetando arquiteturas resilientes de corrotinas” é grátis?
Sim — o texto completo de “Projetando arquiteturas resilientes de corrotinas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Kotlin Academy, atualize para CoddyKit PRO. O curso de Kotlin Academy inclui 4 aulas no total.
O que vou aprender em “Projetando arquiteturas resilientes de corrotinas”?
Combine supervisorScope, lógica de repetição e manipuladores para obter concorrência adequada a ambientes de produção. Você pratica Kotlin Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Kotlin Academy?
Nenhuma experiência prévia é necessária. Kotlin Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Projetando arquiteturas resilientes de corrotinas”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Kotlin Academy?
Sim. Cada aula de Kotlin Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- SupervisorJob vs Job: isolamento de falhas
- CoroutineExceptionHandler: manipulador global de exceções não capturadas
- Propagação de exceções em async/await
- Projetando arquiteturas resilientes de corrotinas