Comment arrêter de corriger les systèmes distribués et commencer à vivre avec Restate
Imaginez ceci : vous écrivez un microservice pour le traitement de paiements. En cours de processus, le réseau vacille, la base de données expire, ou le conteneur redémarre simplement. Que se passe-t-il pour la transaction ? Dans un scénario classique, vous devez implémenter manuellement une logique de retry, suivre l'idempotence, configurer des files d'attente de messages, et très probablement introduire un saga complexe. C'est douloureux, chronophage, et transforme votre code en labyrinthe de gestionnaires d'erreurs.
J'ai récemment découvert Restate, un projet qui aborde ce problème au niveau de l'infrastructure. Les développeurs l'appellent « Durable Execution » — l'exécution de code tolérante aux pannes. L'idée est que votre code devient immortel : si un processus plante, Restate le reprend exactement là où il s'était arrêté, en préservant toutes les variables et l'état.
Qu'est-ce que c'est exactement
Restate est un binaire Rust qui fonctionne comme un serveur proxy et coordinateur pour vos services. Il prend en charge tout le travail fastidieux de gestion d'état et des appels. Vous écrivez du code classique en TypeScript, Python ou Go, utilisez le SDK, et soudain vos fonctions se transforment en workflows fiables.
La principale différence par rapport aux solutions lourdes comme Temporal est que Restate est beaucoup plus facile à prendre en main. Vous n'avez pas besoin d'une configuration massive de bases de données et de workers complexes. Vous pouvez simplement exécuter un binaire unique ou un conteneur Docker et commencer à travailler.
Comment Restate aide en pratique
Le projet inclut plusieurs concepts intéressants qui simplifient véritablement votre vie.
Exécution garantie
Si vous avez appelé une fonction via Restate, elle s'exécutera jusqu'au bout. Point final. Si le serveur exécutant votre code plante, Restate attendra qu'il revienne et continuera l'exécution à partir de la dernière étape réussie. Vous n'avez plus à vous soucier de savoir si l'e-mail a été envoyé deux fois à l'utilisateur ou si de l'argent a été prélevé deux fois.
Minuteries intelligentes et promesses
D'ordinaire, implémenter un délai dans un système distribué est une quête. Vous devez mettre un message dans une file d'attente de délais ou configurer un cron. Dans Restate, vous écrivez simplement ctx.sleep(duration). Le thread ne se bloque pas inutilement : le service peut s'arrêter complètement, et trois jours plus tard, Restate le « réveillera » et continuera l'exécution.
État directement dans le code
Restate vous permet de stocker un état K/V lié à une entité spécifique (par exemple, un ID utilisateur). Cela ressemble à un travail régulier avec des objets, mais en coulisses, Restate garantit que les données sont cohérentes et toujours disponibles avec la requête. C'est particulièrement pratique pour les architectures serverless où les fonctions n'ont généralement pas de mémoire.
À quoi ça ressemble dans le code
Disons que nous devons implémenter un processus d'inscription utilisateur avec confirmation par e-mail. En TypeScript utilisant le SDK Restate, cela ressemblerait à ceci :
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");
}
}
}
});
Ici, ctx.run garantit que l'effet secondaire (l'envoi d'un e-mail) s'exécutera avec succès, et le résultat sera mis en cache. Si la fonction plante après l'envoi, au redémarrage, Restate saute simplement cette étape, sachant qu'elle est déjà terminée.
Le côté technique
Le projet est écrit en Rust, ce qui offre d'excellentes performances. Architecturalement, Restate agit comme un invoker. Il reçoit les requêtes entrantes via HTTP/gRPC, les écrit dans son journal et appelle vos handlers.
Il est intéressant de noter que Restate peut « suspendre » l'exécution. Si votre code attend une réponse d'une API externe ou d'une minuterie, Restate libère les ressources. Lorsque l'événement se produit, il restaure le contexte d'exécution. Cela permet d'exécuter des milliers de processus de longue durée sur du matériel modeste.
Qui devrait essayer
Restate comblera parfaitement les lacunes dans les projets où :
- Il y a de nombreuses chaînes d'appels entre microservices.
- Vous devez construire des chaînes complexes d'actions (sagas, workflows).
- Vous utilisez des agents IA qui doivent attendre longtemps les réponses LLM et préserver le contexte de conversation.
- Il y a des tâches d'exécution différée (rappeler le panier abandonné dans 2 heures).
Le projet est en développement actif, avec près de 4 000 étoiles sur GitHub. Des SDK sont disponibles pour TypeScript/JavaScript, Java/Kotlin, Python, Go et Rust.
Bien sûr, vous ne devriez pas vous précipiter pour intégrer un nouveau composant d'infrastructure dans la production d'une grande banque demain — d'abord, vous devez l'essayer en local. Mais pour les startups ou les nouvelles fonctionnalités dans les projets existants, cela pourrait faire gagner des semaines de développement.
Vous pouvez l'essayer en littéralement quelques minutes :
brew install restatedev/tap/restate-server
restate-server
Et c'est tout, vous avez un environnement local pour exécuter des applications tolérantes aux pannes. C'est peut-être la barrière à l'entrée la plus basse dans le monde de la Durable Execution pour le moment.
Projets similaires