Cómo dejar de corregir sistemas distribuidos y empezar a vivir con Restate
Imagina esto: estás escribiendo un microservicio para procesamiento de pagos. A mitad del proceso, la red parpadea, la base de datos supera el tiempo de espera, o el contenedor simplemente se reinicia. ¿Qué pasa con la transacción? En un escenario clásico, necesitas implementar manualmente lógica de reintentos, rastrear idempotencia, configurar colas de mensajes, y muy probablemente introducir algún saga complejo. Es doloroso, consume mucho tiempo, y convierte tu código en un laberinto de manejadores de errores.
Descubrí Restate recientemente, un proyecto que aborda este problema a nivel de infraestructura. Los desarrolladores lo llaman "Ejecución Duradera" — ejecución de código tolerante a fallos. La idea es que tu código se vuelve inmortal: si un proceso falla, Restate lo reanuda justo donde lo dejó, preservando todas las variables y el estado.
¿Qué es exactamente esto?
Restate es un binario en Rust que funciona como servidor proxy y coordinador para tus servicios. Se encarga de todo el trabajo sucio de gestión de estado y llamadas. Escribes código normal en TypeScript, Python, o Go, usas el SDK, y de repente tus funciones se convierten en flujos de trabajo confiables.
La diferencia principal con soluciones más pesadas como Temporal es que Restate es mucho más fácil de comenzar. No necesitas una configuración masiva de bases de datos y workers complejos. Simplemente puedes ejecutar un único binario o contenedor Docker y empezar a trabajar.
Cómo Restate ayuda en la práctica
El proyecto incluye varios conceptos geniales que realmente simplifican tu vida.
Ejecución garantizada
Si llamaste a una función a través de Restate, se ejecutará hasta el final. Punto. Si el servidor que ejecuta tu código falla, Restate esperará a que vuelva y continuará la ejecución desde el último paso exitoso. Ya no necesitas preocuparte por si el correo electrónico se envió dos veces al usuario o si se cobró dos veces el dinero.
Temporizadores y promesas inteligentes
Usualmente, implementar un retraso en un sistema distribuido es una odisea. Necesitas poner un mensaje en una cola de retrasos o configurar un cron job. En Restate, simplemente escribes ctx.sleep(duration). El hilo no se bloquea inútilmente: el servicio puede apagarse completamente, y tres días después Restate lo "despertará" y continuará la ejecución.
Estado directamente en el código
Restate te permite almacenar estado K/V vinculado a una entidad específica (por ejemplo, un ID de usuario). Se parece al trabajo regular con objetos, pero bajo el capó Restate garantiza que los datos sean consistentes y siempre estén disponibles junto con la solicitud. Esto es especialmente conveniente para arquitecturas serverless donde las funciones típicamente no tienen memoria.
Cómo se ve en el código
Digamos que necesitamos implementar un proceso de registro de usuario con confirmación por correo electrónico. En TypeScript usando el SDK de Restate, se vería algo así:
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");
}
}
}
});
Aquí ctx.run garantiza que el efecto secundario (enviar un correo electrónico) se ejecutará exitosamente, y el resultado se almacenará en caché. Si la función falla después de enviar, al reiniciar Restate simplemente omite este paso, sabiendo que ya se realizó.
El lado técnico
El proyecto está escrito en Rust, lo que proporciona un excelente rendimiento. Arquitecturalmente, Restate actúa como un invocador. Recibe solicitudes entrantes sobre HTTP/gRPC, las escribe en su log, y llama a tus manejadores.
Curiosamente, Restate puede "suspender" la ejecución. Si tu código está esperando una respuesta de una API externa o un temporizador, Restate libera recursos. Cuando ocurre el evento, restaura el contexto de ejecución. Esto permite ejecutar miles de procesos de larga duración en hardware modesto.
Quién debería probarlo
Restate llenará perfectamente los vacíos en proyectos donde:
- Hay muchas cadenas de llamadas entre microservicios.
- Necesitas construir cadenas complejas de acciones (sagas, flujos de trabajo).
- Estás usando agentes de IA que necesitan esperar mucho tiempo las respuestas de LLM y preservar el contexto de la conversación.
- Hay tareas de ejecución diferida (recordar sobre un carrito abandonado en 2 horas).
El proyecto se está desarrollando activamente, con casi 4,000 estrellas en GitHub. Los SDK están disponibles para TypeScript/JavaScript, Java/Kotlin, Python, Go, y Rust.
Por supuesto, no deberías apresurarte a incorporar un nuevo componente de infraestructura en producción de un banco grande mañana — primero necesitas probarlo localmente. Pero para startups o nuevas características en proyectos existentes, podría ahorrar semanas de desarrollo.
Puedes probarlo en literalmente un par de minutos:
brew install restatedev/tap/restate-server
restate-server
Y eso es todo, tienes un entorno local para ejecutar aplicaciones tolerantes a fallos. Quizás esta es la barrera de entrada más baja al mundo de la Ejecución Duradera en este momento.
Proyectos relacionados