>_ DevTrendspt

Idioma

Início

Linguagens

Seções

Frontend Backend Mobile DevOps AI / ML GameDev Blockchain Segurança
Rust

Como Parar de Corrigir Sistemas Distribuídos e Começar a Viver com Restate

4.112 estrelas

Imagine o seguinte: você está escrevendo um microsserviço para processamento de pagamentos. No meio do processo, a rede falha, o banco de dados dá timeout, ou o container simplesmente reinicia. O que acontece com a transação? No cenário clássico, você precisa implementar manualmente lógica de retry, rastrear idempotência, configurar filas de mensagens e, muito provavelmente, introduzir algum saga complexo. É doloroso, consome tempo e transforma seu código em um labirinto de handlers de erro.

Recentemente descobri o Restate, um projeto que ataca esse problema no nível da infraestrutura. Os desenvolvedores chamam de "Execução Durável" — execução de código tolerante a falhas. A ideia é que seu código se torna imortal: se um processo trava, o Restate o retoma exatamente de onde parou, preservando todas as variáveis e estado.

Restate overview

O que exatamente é isso

Restate é um binário em Rust que funciona como um servidor proxy e coordenador para seus serviços. Ele assume todo o trabalho pesado de gerenciamento de estado e chamadas. Você escreve código comum em TypeScript, Python ou Go, usa o SDK e, de repente, suas funções se transformam em workflows confiáveis.

A principal diferença para soluções mais pesadas como o Temporal é que o Restate é muito mais fácil de começar. Você não precisa de uma configuração massiva de bancos de dados e workers complexos. Você pode simplesmente rodar um único binário ou container Docker e começar a trabalhar.

Como o Restate ajuda na prática

O projeto inclui vários conceitos interessantes que realmente simplificam sua vida.

Execução garantida

Se você chamou uma função através do Restate, ela vai executar até o final. Ponto final. Se o servidor que executa seu código trava, o Restate espera ele voltar e continua a execução a partir do último passo bem-sucedido. Você não precisa mais se preocupar se o e-mail foi enviado duas vezes para o usuário ou se o dinheiro foi cobrado duas vezes.

Timers e promises inteligentes

Normalmente, implementar um delay em um sistema distribuído é uma jornada. Você precisa colocar uma mensagem em uma fila de delay ou configurar um cron job. No Restate, você simplesmente escreve ctx.sleep(duration). A thread não bloqueia inutilmente: o serviço pode ser desligado completamente, e três dias depois o Restate vai "acordá-lo" e continuar a execução.

Estado direto no código

O Restate permite armazenar estado K/V vinculado a uma entidade específica (por exemplo, um ID de usuário). Parece trabalho normal com objetos, mas por baixo dos panos o Restate garante que os dados são consistentes e sempre disponíveis junto com a requisição. Isso é especialmente conveniente para arquiteturas serverless onde funções tipicamente não têm memória.

Como fica no código

Digamos que precisamos implementar um processo de registro de usuário com confirmação por e-mail. Em TypeScript usando o SDK do Restate, ficaria algo assim:

import * as restate from "@restatedev/restate-sdk";

const userService = restate.service({
  name: "users",
  handlers: {
    register: async (ctx: restate.Context, user: { id: string, email: string }) => {
      // Сохраняем состояние
      ctx.set("status", "pending");

      // Отправляем письмо (Restate гарантирует, что это случится 1 раз)
      await ctx.run(() => sendWelcomeEmail(user.email));

      // Ждем подтверждения или таймаута в 24 часа
      const confirmed = await ctx.awakeable<boolean>("email-confirmed");
      
      if (confirmed) {
        ctx.set("status", "active");
      }
    }
  }
});

Aqui ctx.run garante que o efeito colateral (enviar o e-mail) vai executar com sucesso, e o resultado será cacheado. Se a função travar depois de enviar, ao reiniciar o Restate simplesmente pula esse passo, sabendo que já foi feito.

O lado técnico

O projeto é escrito em Rust, o que oferece excelente performance. Arquiteturalmente, o Restate atua como um invocador. Ele recebe requisições entrantes via HTTP/gRPC, escreve no seu log e chama seus handlers.

Curiosamente, o Restate pode "suspender" a execução. Se seu código está esperando uma resposta de uma API externa ou um timer, o Restate libera os recursos. Quando o evento ocorre, ele restaura o contexto de execução. Isso permite rodar milhares de processos de longa duração em hardware modesto.

Quem deveria experimentar

O Restate vai preencher perfeitamente lacunas em projetos onde:

  • Existem muitas cadeias de chamadas entre microsserviços.
  • Você precisa construir cadeias complexas de ações (sagas, workflows).
  • Você está usando agentes de IA que precisam esperar muito tempo por respostas de LLMs e preservar o contexto da conversa.
  • Existem tarefas de execução adiada (lembrete de carrinho abandonado em 2 horas).

O projeto está em desenvolvimento ativo, com quase 4.000 estrelas no GitHub. SDKs estão disponíveis para TypeScript/JavaScript, Java/Kotlin, Python, Go e Rust.

Claro, você não deveria se apressar para colocar um novo componente de infraestrutura na produção de um grande banco amanhã — primeiro, você precisa testar localmente. Mas para startups ou novas funcionalidades em projetos existentes, isso pode economizar semanas de desenvolvimento.

Você pode testar em literalmente alguns minutos:

brew install restatedev/tap/restate-server
restate-server

E pronto, você tem um ambiente local para rodar aplicações tolerantes a falhas. Talvez essa seja a menor barreira de entrada para o mundo da Execução Durável no momento.

Projetos relacionados