0Pricing
Kotlin Academy · Aula

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 delays

Verificaçã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

  1. SupervisorJob vs Job: isolamento de falhas
  2. CoroutineExceptionHandler: manipulador global de exceções não capturadas
  3. Propagação de exceções em async/await
  4. Projetando arquiteturas resilientes de corrotinas
← Voltar para Kotlin Academy