Flawless - Moteur d’exécution durable pour Rust
(flawless.dev)- Flawless est un moteur d’exécution de calculs durables qui aide le code à aller jusqu’au bout même en cas de panne
- Les workflows s’écrivent comme de simples fonctions Rust, mais sont compilés en WebAssembly plutôt qu’en code natif, puis exécutés dans un environnement déterministe
- Les effets de bord non déterministes n’apparaissent qu’aux points de contact avec le monde extérieur, comme les requêtes HTTP ou la génération de nombres aléatoires, et Flawless les enregistre dans des logs
- Si l’exécution est interrompue, Flawless utilise les logs enregistrés pour revenir au même état, sans répéter les effets de bord déjà exécutés
- Les développeurs peuvent représenter l’état persistant avec le code et les variables locales, sans devoir modéliser eux-mêmes tout l’état dans une base de données, ce qui permet de reprendre après un redémarrage serveur à partir du point d’interruption
Un modèle d’exécution qui exprime l’état persistant dans le code
- Flawless est un moteur de calculs durables conçu pour exécuter le code jusqu’à son terme, même en cas de panne matérielle ou logicielle
- Les expériences utilisateur complexes exigent des interfaces et des états complexes, mais il est difficile de modéliser directement tout l’état dans une base de données
- Les applications modernes ont besoin d’un stockage persistant pour que l’utilisateur ne perde pas sa progression, même s’il recharge la page par erreur
- Flawless vise à faire modéliser l’état persistant dans le code et les variables locales, afin d’exprimer plus facilement les comportements complexes d’une application
Exécution basée sur WebAssembly et reprise après panne
- Les workflows sont écrits comme de simples fonctions Rust et peuvent contenir une logique arbitraire
- Les fonctions sont compilées en WebAssembly plutôt qu’en code natif, puis exécutées dans un environnement entièrement déterministe
- La non-déterminisme n’est introduit qu’au moment des interactions avec le monde extérieur, comme l’exécution de requêtes HTTP ou la génération de nombres aléatoires
- Flawless conserve ces logs d’effets de bord non déterministes et les utilise pour la reprise
- Si l’exécution d’un workflow s’interrompt, il le relance pour rattraper exactement le même état
- Les effets de bord déjà exécutés ne sont pas rejoués
- La quantité de données à stocker est minimisée, le reste étant recalculé à la demande en cas de panne
- Ce modèle d’exécution permet de mieux observer le comportement de l’ensemble du système
- Il devient possible d’analyser précisément le chemin d’exécution de workflows terminés ou en cours
- Grâce à l’environnement d’exécution déterministe, les bugs difficiles à reproduire deviennent plus faciles à traiter
- Les développeurs peuvent réduire la charge liée à la persistance d’état et se concentrer davantage sur la logique métier
- Même si un redémarrage serveur est nécessaire pour maintenance, il suffit de redémarrer le moteur Flawless pour que les workflows reprennent à partir du point d’arrêt
- Au 9 décembre 2024, Flawless Beta 3 est disponible
1 commentaires
Commentaires sur Hacker News
Je me demande comment la gestion des versions des workflows est traitée. À mon avis, c’est le problème le plus difficile dans des systèmes comme Temporal/Cadence
La mise à niveau ne réussit que si le nouveau code peut rejouer exactement le journal existant des effets de bord. L’idée est de rattraper l’exécution avec le nouveau code, puis de continuer à l’exécuter tel quel une fois le rattrapage terminé
Si le nouveau code diverge de l’historique existant, la mise à niveau échoue et on revient à l’ancien code. Dans ce cas, une intervention humaine est nécessaire pour vérifier ce qui s’est mal passé
Il existe d’autres approches, mais en pratique c’est celle qui me semble la plus simple à comprendre et à utiliser. Même pendant le développement, on peut tester si le code diverge en réutilisant les journaux existants
Est-ce que vous voulez maintenir plusieurs versions en parallèle, ou bien faut-il aussi un moyen de migrer les exécutions en cours vers la dernière définition de workflow ?
J’ai l’impression que notre domaine se rapproche de plus en plus de l’architecture ou de la médecine. Grâce à ce genre de technologie, on peut sortir du bricolage pour entrer dans une véritable culture de l’ingénierie
Pour faire court, je me demande comment on empêche dans ce type de système que l’effet d’une attaque DoS soit persisté
L’architecture relève davantage de la gestion d’opinions subjectives sous contraintes réglementaires, et la médecine d’un savoir empirique validé par l’expérimentation. Il est difficile de dire que l’une ou l’autre ressemble vraiment à l’ingénierie
L’architecture est plus proche d’une forme d’art, et les écoles d’architecture sont souvent rattachées aux beaux-arts
La médecine est une science appliquée comme l’ingénierie, mais ce n’est pas un domaine de l’ingénierie en soi
Je me demande si ce déterminisme s’étend aussi aux calculs en virgule flottante
Dans les jeux multijoueurs, l’état des clients accumulait progressivement une dérive à cause des calculs en virgule flottante, donc il fallait les resynchroniser périodiquement avec l’état du serveur, et historiquement c’était un vrai point douloureux
Voir https://webassembly.org/docs/faq/#why-is-there-no-fast-math-... et https://github.com/WebAssembly/design/blob/main/Nondetermini...
https://asawicki.info/news_1741_myths_about_floating-point_n...
À une époque, les résultats CPU pouvaient eux aussi varier selon le chemin d’exécution. Voir le tweet dans l’article
f64pourrait être une option, ou si ce n’est pas réaliste en termes de complexité et de tailleJe me demande où l’état des effets de bord est stocké. Par exemple, si on a une AWS Lambda qu’on veut rendre idempotente, Lambda n’a pas de stockage local persistant entre les exécutions
À moins de monter quelque chose comme un volume EBS, l’état n’est pas conservé, donc on peut supposer qu’il est stocké dans une base de données ?
J’aime bien l’animation qui montre le principe de base et le fonctionnement. Elle est vraiment très bien faite
Le code n’est pas très joli, mais l’implémentation est assez intuitive, donc si vous voulez y jeter un œil, c’est ici : https://flawless.dev/js/how-does-it-work-animation.js
Ça a l’air intéressant, mais je me demande si cette façon de marquer une fonction comme ayant des effets de bord est vraiment simple à rendre infaillible
Dans l’exemple, je suppose que la génération aléatoire est un effet de bord parce qu’elle provient du générateur de nombres aléatoires fourni par flawless. Est-ce que cela aurait aussi été possible avec une fonction Rust ordinaire ?
J’imagine qu’il doit aussi y avoir une sorte de harnais de test permettant aux développeurs de vérifier leurs workflows
WebAssembly exige de déclarer explicitement les appels à l’hôte dans le module. Si on essaie d’utiliser d’autres appels à l’hôte que ceux fournis par flawless, le module ne peut pas être instancié
Plusieurs efforts de standardisation sont aussi en cours dans l’écosystème WebAssembly. Par exemple, si on utilise la crate Rust
randpuis qu’on compile en WebAssembly, la génération aléatoire passe par des fonctions hôte WASIEn attendant que
wasi,wasi-httpet d’autres soient standardisés, nous exposons pour l’instant notre propre interfaceBien sûr, il y a aussi un gros inconvénient. Tout le code Rust ne peut pas être compilé en WebAssembly. Malgré cela, je pense qu’un mode de refus par défaut qui garantit qu’aucun effet de bord involontaire ne peut jamais se produire est préférable
flawless, on dirait qu’au lieu de donner accès à tout l’écosystème Rust, il faudra utiliser quelque chose commestd::flawlessLe harnais résoudra probablement la plupart des problèmes, mais je me demande jusqu’où il sera possible de mapper des fonctionnalités
Pour l’instant, cela ressemble davantage à un runtime de scripting qui utilise Rust
Cela ressemble à une alternative en Rust à Temporal utilisant WASM comme runtime. J’aime beaucoup.
Je suis le fondateur de windmill.dev, et nous avons nous aussi un moteur durable écrit en Rust. Le nôtre est toutefois bien moins élégant. Nous découpons les workflows en étapes explicites Python/TypeScript/Go/Bash et, pour reprendre à une étape inachevée, nous redémarrons depuis la dernière étape en persistant le résultat de chaque étape dans le
jsonbd’une base PostgresLes cas d’usage sont clairement différents, et flawless semble suffisamment léger, comme indiqué sur le site, pour modéliser l’état des flux UI et même monter jusqu’à des millions d’instances sur de petits serveurs
C’est fantastique. J’espère qu’un jour Rust fera tourner tous les systèmes distribués
« Tout programme concurrent suffisamment complexe écrit dans un autre langage inclut, comme solution de fortune, une demi-implémentation d’Erlang, boguée, lente et basée sur une spécification non officielle » — première loi de la programmation de Virding
C’est assez différent d’Erlang. Erlang a surtout été conçu pour développer des logiciels alors qu’on ne disposait que d’équipements prototypes avec de nombreux problèmes matériels
Pour moi, les deux approches paraissent opposées. Flawless peut se retrouver coincé dans une boucle à tenter d’achever un workflow qui plante en cours de route, alors qu’Erlang peut volontiers jeter 50 % du trafic qui tombe sur un bug matériel
Erlang le résout essentiellement en éliminant l’état persistant. Presque tout l’état se trouve dans des files de messages ou dans une base externe
Flawless semble résoudre le problème avec une technique proche du journalisation de système de fichiers, sans être exactement la même. Il enregistre les effets de bord au moment où ils se produisent
La journalisation de système de fichiers sert à réexécuter après un crash, alors qu’ici l’objectif est d’éviter d’avoir à réexécuter
On ne voit pas encore clairement dans quels domaines cela conviendra le mieux, mais le recouvrement avec les domaines où Erlang excelle ne semble pas complet
Très sympa. Ambient, le runtime de jeu WASM, a un problème similaire. Il y a des processus concurrents et il peut être nécessaire de réessayer les interactions, donc l’approche montrée ici est intéressante
Je me demande toutefois quelle est la relation avec Lunatic. Lunatic est-il toujours en cours de développement, est-ce un projet annexe, ou est-ce complètement séparé ?
https://lunatic.solutions/
https://kolobara.com
« Imaginez lancer un calcul arbitraire et avoir la garantie que le système s’exécutera jusqu’à son terme et que chaque opération sera effectuée exactement une fois »
Je me demande comment cela est garanti. Dans un système distribué, la livraison exactement une fois n’est-elle pas impossible ?
Si le système peut continuer à avancer, alors les messages sont livrés exactement une fois
S’il faut une preuve d’existence, NFSv3 faisait déjà fonctionner cela dans les années 1980. Je ne sais pas si c’était le premier