O Problema da Execução Durável: Uma História Familiar

Imagine um processo de negócio com múltiplas etapas: validar uma reclamação, rodar verificações de segurança, processar um pagamento, enviar notificações. No meio do caminho, o servidor cai. O que acontece depois?

Em arquiteturas tradicionais, a resposta é muitas vezes "depende." Talvez a operação expire e dispare processamento duplicado. Talvez um estado parcial corrompa o que vem a seguir. Para workflows que duram minutos, horas ou até dias, interrupções são muito prováveis.

Esse é o problema da execução durável: garantir que um processo multi-etapas seja concluído de forma confiável, mesmo através de falhas, reinicializações e deploys. A indústria produziu várias soluções:

  • Engines de orquestração externos (ex: Temporal, AWS Step Functions) — testados em batalha, mas exigem infraestrutura dedicada e introduzem uma dependência externa crítica.
  • Serviços de workflow gerenciados em nuvem — eliminam a sobrecarga operacional, mas introduzem vendor lock-in e preocupações regulatórias.
  • Sistemas caseiros baseados em fila — evitam dependências externas, mas trocam por complexidade própria: cada equipe implementa sua própria lógica de retry, gerenciamento de estado e fluxos de compensação.

O Airbnb enfrentou todos esses tradeoffs em várias equipes. Em vez de cada serviço reinventar a roda, eles construíram o Skipper — um engine de workflow embarcado que roda dentro de cada serviço, usando o banco de dados que o serviço já utiliza.

Fonte: Airbnb Engineering Blog

Airbnb Skipper embedded workflow engine architecture diagram showing service and database interaction Algorithm Concept Visual

Design Central do Skipper: Workflows e Actions

O Skipper se baseia em duas abstrações:

  1. Workflows — definem a lógica de orquestração: o que acontece em qual ordem e sob quais condições.
  2. Actions — encapsulam operações individuais (chamadas de API, atualizações de banco, notificações). Cada action é automaticamente checkpointed, para que seu resultado sobreviva a crashes e reinicializações.

Um Exemplo Concreto

Aqui está um workflow durável para processar a revisão de fotos de um anúncio:

class ListingPublicationWorkflow : Workflow() {
    private val actions = actions()
    @StateField val photosApproved: Boolean? = false

    @WorkflowMethod
    suspend fun publishListing(submission: ListingSubmission): PublicationResult {
        // Envia fotos para revisão
        val reviewId = actions.submitPhotosForReview(submission.getListingId())

        // Aguarda a conclusão da revisão (manual ou automatizada)
        val reviewTimedOut = waitUntil(() -> photosApproved != null,
            Duration.ofHours(24))

        if (reviewTimedOut || !photosApproved) {
            actions.notifyHost(submission.getHostId(), "Fotos precisam de ajustes")
            return PublicationResult.rejected("Revisão de fotos falhou")
        }

        // Publica o anúncio
        actions.activateListing(submission.getListingId())
        actions.notifyHost(submission.getHostId(), "Seu anúncio está no ar!")
        return PublicationResult.success(submission.getListingId())
    }

    @SignalMethod
    fun completePhotoReview(approved: Boolean) {
        photosApproved = approved
    }
}

Esse código é natural: enviar fotos, aguardar revisão, publicar. Não há lógica de retry, gerenciamento de fila ou coordenação assíncrona visível no workflow.

Como a Durabilidade Funciona

Quando um workflow inicia, o Skipper faz checkpoint do resultado de cada action no banco de dados. Se o workflow precisar esperar (via waitUntil), o Skipper persiste o estado atual e o workflow hiberna, sem consumir recursos computacionais.

Quando as condições mudam — um sinal chega, um timer expira ou o serviço reinicia — o Skipper reproduz o método do workflow desde o início. Actions já executadas não são reexecutadas; elas retornam seus resultados checkpointed instantaneamente. O workflow continua de onde parou.

Isso é fundamentalmente diferente de sistemas de orquestração event-sourced. O Skipper persiste campos de estado diretamente — não há um log de eventos para reproduzir. Isso torna a execução mais leve, especialmente para workflows com muitos sinais ou históricos longos, embora troque alguma auditabilidade por essa eficiência.

Cloud infrastructure diagram illustrating durable execution with Skipper across multiple services Development Concept Image

O Caminho Feliz: Saindo do Caminho

A maioria dos engines de workflow impõe overhead em toda execução, mesmo quando nada dá errado. Engines de orquestração externos exigem round-trips de rede para um cluster central para cada invocação de atividade.

O Skipper adota uma abordagem diferente. Quando um workflow inicia, duas coisas acontecem no nível do banco de dados:

  1. A instância do workflow é criada
  2. Uma tarefa de timeout atrasada é agendada como garantia de durabilidade

Então o workflow executa inteiramente in-process. Actions rodam como chamadas de método normais em uma fila de execução em memória, checkpoints são agrupados, e o workflow pode ser concluído sem qualquer coordenação adicional.

A tarefa atrasada funciona como uma rede de segurança: se o processo cair no meio da execução, o agendador persistente retoma o workflow após o período de lease expirar e o reproduz. Se o workflow for concluído normalmente, a tarefa de timeout é descartada inofensivamente.

Resultado: No caso feliz (sem crashes), o Skipper adiciona muito pouco overhead — apenas algumas escritas no banco. O workflow executa quase como se não houvesse engine de workflow algum.

Tradeoffs Principais

O Que Você GanhaO Que Você Troca
Sem infraestrutura para gerenciar (sem cluster separado)Métodos de workflow devem ser determinísticos (sem efeitos colaterais, aleatoriedade ou lógica dependente de tempo)
Usa banco de dados existente (MySQL, DynamoDB)Execução pelo menos uma vez — actions podem executar mais de uma vez em casos extremos; actions devem ser idempotentes
Modelo de programação simples (classes Java/Kotlin)Complexidade de evolução — mudar a estrutura de um workflow pode quebrar workflows em andamento; estratégias de versionamento são necessárias
Escalabilidade independente por serviçoNão adequado para orquestração cross-language ou cross-service

Limitações e Cuidados

  • Determinismo é difícil. Desenvolvedores novos no padrão frequentemente introduzem não-determinismo acidentalmente (ex: chamar System.currentTimeMillis() dentro de um método de workflow). Isso quebra a reprodução.
  • Idempotência é obrigatória. Como actions podem executar mais de uma vez, toda action deve ser segura para rodar múltiplas vezes.
  • Versionamento de workflow é doloroso. Não há ferramentas de migração embutidas. Equipes precisam criar novas versões de métodos, migrar tráfego e depreciar versões antigas.
  • Debugging é mais difícil. Timestamps de log e sequências de chamadas refletem reproduções, não a execução original. Melhores ferramentas de observabilidade (visualização de reprodução) ajudariam.

Próximos Passos para Aprendizado

Se esse padrão te interessou, considere explorar:

  • Temporal — o engine de orquestração externo mais popular para execução durável
  • AWS Step Functions — uma alternativa gerenciada em nuvem
  • Apache Airflow — para orquestração de pipelines de dados

Para um mergulho prático em sistemas distribuídos na AWS, veja nosso guia sobre escalando Python com Ray em cluster na nuvem.

Developer writing Java Kotlin workflow code for durable execution with Skipper Programming Illustration

Conclusão: Quando Usar um Engine de Workflow Embarcado

Execução durável de workflow é uma capacidade fundamental para sistemas distribuídos confiáveis. O Skipper representa um ponto específico no espaço de design: um engine embarcado que troca orquestração centralizada por simplicidade operacional.

Essa abordagem não serve para todas as situações. Mas para serviços que buscam execução durável sem overhead de infraestrutura — particularmente onde minimizar dependências é primordial — o modelo embarcado oferece vantagens convincentes.

O insight central se generaliza além da implementação do Airbnb: execução baseada em reprodução com actions checkpointed pode fornecer durabilidade sem serviços de coordenação.

Leitura Adicional

Este conteúdo foi elaborado com o auxílio de ferramentas de IA, com base em fontes confiáveis, e revisado pela nossa equipe editorial antes da publicação. Não substitui o aconselhamento de um profissional especializado.