- Le cœur de l’exécution durable n’est pas l’infrastructure elle-même, mais la conservation de l’état du workflow ; si la progression est enregistrée, la relance et la reprise sont possibles
- Obelisk enregistre la progression du workflow dans un journal d’exécution et la rejoue à partir de l’historique persistant, avec une structure adaptée aux nouvelles tentatives des activités
- SQLite fournit un état durable transactionnel sous forme de fichier local, sans service de base de données séparé, sans saut réseau ni plan de contrôle supplémentaire
- Litestream diffuse de façon asynchrone les modifications de SQLite vers un stockage objet compatible S3, mais si le volume disparaît avant la copie, les écritures les plus récentes peuvent être perdues
- Obelisk prend aussi en charge Postgres, plus adapté lorsqu’il faut une disponibilité plus élevée, une meilleure extensibilité partagée ou les propriétés d’une base de données en réseau
Modèle opérationnel de SQLite et Litestream
- Litestream peut diffuser de façon asynchrone les modifications de SQLite vers un stockage objet compatible S3
- Cela permet de garder l’état de travail au plus près de l’environnement d’exécution tout en copiant la base de données à l’extérieur pour la sauvegarde, la migration ou l’inspection
- En raison de la nature de la réplication asynchrone, si le volume SQLite disparaît avant la copie, les dernières écritures locales peuvent être perdues lors de la restauration
- La structure consiste à exécuter le serveur Obelisk avec la base de données SQLite, à la sauvegarder avec Litestream, puis à laisser les observateurs récupérer la base nécessaire lorsque c’est utile
- Le même fichier SQLite peut servir à la relecture locale, au débogage et à la compréhension de ce qu’un agent a réellement exécuté
Périmètre d’usage pertinent et critères de choix de Postgres
- Les agents IA et les workflows générés par l’IA ont souvent un comportement en rafales et restent expérimentaux ; une configuration avec de petites unités d’état autonomes par agent ou par locataire est donc plus simple à comprendre
- Une approche avec plusieurs petits serveurs dans des micro-VM ou des conteneurs, chacun avec sa propre base SQLite et sa sauvegarde sur stockage objet, peut être plus simple, moins coûteuse et mieux isolée face aux pannes qu’un grand système partagé fonctionnant en permanence
- Si la réplication asynchrone vers le stockage objet ne correspond pas au modèle de durabilité souhaité, ou si une disponibilité plus élevée, une extensibilité partagée plus large ou les propriétés d’une base de données en réseau sont nécessaires, Postgres est plus adapté
- De nombreux systèmes de workflow n’ont pas besoin d’un tel niveau d’infrastructure dès le premier jour, et il n’est pas nécessaire de démarrer avec une infrastructure plus importante que les besoins réels en matière d’état
- Une base de données SQLite locale, des sauvegardes Litestream vers S3 et une combinaison de workers peu coûteux peuvent suffire à construire un système durable avec peu d’infrastructure, ce qui peut constituer un choix par défaut raisonnable dans le domaine des agents IA
Vous voulez continuer à recevoir des sujets tech sélectionnés ?
Suivez le canal Telegram.
@GeekNewsFR
1 commentaires
Commentaires sur Hacker News
J’ai commencé à construire des workflows avec Temporal ; pour une appli locale, le déploiement reste assez léger, et dans une installation locale isolée on utilise SQLite
La gestion des retries d’API ainsi que l’organisation des workflows et des tâches deviennent vraiment simples, donc je recommande d’essayer. Philosophiquement, c’est exactement dans la même direction que ce que propose cet article, mais avec en plus une interface très riche et flexible, bien adaptée aux agents. Il est aussi facile d’examiner les workflows via l’interface web et de revoir l’exécution des agents
Temporal apporte au système une fiabilité bien plus élevée, presque gratuitement. Les systèmes distribués et fiables sont difficiles, donc je pense qu’il vaut mieux éviter de réinventer la roue
Si vous voulez pouvoir inspecter facilement une base SQLite, comprendre ce qui se passe dans un workflow, composer des tâches individuelles et rendre les workflows simples à invoquer, Temporal vaut le détour
Avec ça, j’ai presque cessé d’utiliser des fichiers pour les agents. Markdown et JSON sont très bien, mais pour de petites applis locales, ça ressemble à un piège. Les LLM se débrouillent bien avec SQLite, et on peut ensuite en faire le rendu dans le format voulu, comme Markdown ou JSON. Si l’agent peut interroger uniquement certaines lignes au lieu de lancer jq ou de faire du grep sur du Markdown, on économise aussi beaucoup de tokens. On obtient un système de gestion de données portable et auto-contenu, qui impose plus de discipline à la structure des données que plusieurs fichiers séparés. Et si un petit projet local grossit ou se formalise davantage, on peut ensuite passer à MySQL/Postgres, avec déjà un schéma et une discipline de données en place
Temporal devient bien plus complexe à grande échelle. Exploiter Cassandra n’a rien d’agréable, et Ringpop comme TChannel sont difficiles à déboguer quand il y a un problème. Le support des backends SQL, à cause des exigences de cohérence, ne permet pas de réplicas à scalabilité horizontale et se limite à une seule instance
Selon la manière dont le code est écrit, modifier du code déjà embarqué dans les workflows devient aussi compliqué. Les changements qui modifient l’ordre des événements dans l’historique cassent le déterminisme des workers déjà déployés
Nous utilisons beaucoup Temporal : tous ceux qui ont commencé avec pour du scripting simple ou de l’automatisation l’adorent, et tous ceux qui ont construit dessus de vrais systèmes de production le détestent. C’est peut-être un manque de maîtrise opérationnelle, mais l’image très rose qu’on voit dans ces commentaires ne correspond pas à mon expérience
Je ne l’ai pas fait moi-même, mais j’aimerais entendre plus de retours d’expérience concrets
Je ne comprends pas cette obsession pour l’idée d’utiliser SQLite dans des applications réellement en production. SQLite est une base de données embarquée, donc pas du tout adaptée à la gestion de la concurrence
C’est précisément pour ce genre de chose qu’il existe des serveurs de bases de données comme Postgres ou MySQL. Leur rôle global est de permettre à plusieurs processus, sur des machines différentes, de modifier des données simultanément
C’est un principe de base de l’informatique, et le camp du « SQLite pour tout » semble manquer un peu d’expérience
SQLite est une excellente base de données de production pour de nombreuses charges de travail réelles, et cela est largement documenté. Comme c’est très différent de Postgres, il faut apprendre un ensemble de techniques complètement différent
Un angle de vue consiste à dire que SQLite peut très bien convenir aux parties d’un système qui se prêtent naturellement à un partitionnement fort
net/httpde Go, suffise à absorber toute la charge qu’un service donné peut raisonnablement imaginer. Encore plus si l’on peut faire évoluer le matériel avec le temps, et SQLite peut monter simplement jusqu’à plusieurs centaines de milliers de TPSCe à quoi on renonce vraiment, c’est surtout la haute disponibilité / le basculement et la reprise après sinistre, mais il existe aussi des solutions à cela. Les systèmes à serveur unique sont en général étonnamment robustes, notamment parce qu’en l’absence de plan de contrôle complexe, la disponibilité tend souvent à diminuer à mesure que le système grossit
J’aime réévaluer les « bonnes pratiques » établies à la lumière de l’évolution technique, surtout quand cela va dans le sens de plus de simplicité. Faire tourner un site de réseau social familial sur une seule base SQLite sur un VPS, c’est excellent. Il y a environ 15 utilisateurs et pratiquement aucune maintenance. Mon instance FreshRSS et ma page « now » tournent aussi sur SQLite
Au travail aussi, j’ai utilisé SQLite pour toutes sortes de choses au fil des dernières décennies : comme file de tâches temporaire, pour ingérer et interroger rapidement beaucoup de logs en local, et pour les afficher/filtrer en temps réel avec l’excellent https://github.com/simonw/datasette de simonw
Plutôt que « SQLite pour tout », je dirais plutôt « SQLite dans bien plus d’endroits qu’on ne l’imagine »
Le travail de kentonv/Cloudflare sur SQLite à l’edge a peut-être un peu popularisé cette idée, mais c’était déjà une tendance existante. https://blog.cloudflare.com/sqlite-in-durable-objects/
Vouloir connaître et exploiter ces petits cas d’usage utiles n’est pas un signe de manque d’expérience, c’est peut-être au contraire un signe d’expérience
SQLite est probablement plus utilisé que tous les autres moteurs de base de données réunis. Il existe des milliards de copies de SQLite dans la nature. On en trouve dans les appareils Android, les iPhone et appareils iOS, les Mac, les installations Windows 10/11, Firefox/Chrome/Safari, Skype, iTunes, le client Dropbox, TurboTax et QuickBooks, PHP et Python, la plupart des TV et décodeurs, la plupart des systèmes multimédias embarqués des voitures, et d’innombrables applications
https://sqlite.org/mostdeployed.html
Cela rend la scalabilité beaucoup plus facile à comprendre. Il suffit de découper, répliquer le schéma, puis recommencer. En pratique, on ajoute un shard supplémentaire tous les N utilisateurs
En échange, on récupère d’autres problèmes, comme les requêtes inter-shards — par exemple pour l’analytique — et la manière d’équilibrer la charge quand des utilisateurs partent ou vieillissent
Mais on évite tout le problème de montée en charge des index partagés causé par les insertions/mises à jour à grande échelle
Cela devient moins une base de données relationnelle qu’une base de données hiérarchique
J’ai remplacé tout ce qui suit par du Go + SQLite : Intercom, Zendesk, email marketing, Kanban, Todo, la stack de paiement, l’issue tracker, le forum, le monitoring d’uptime, un clone de PagerDuty
Comme je vends des dizaines de produits, je me suis dit : pourquoi ne pas tout faire moi-même ?
Tout tourne sur le même serveur et consomme très peu de mémoire. J’ai remplacé tous les outils SaaS que j’utilisais par ces solutions
En migrant vers un serveur dédié, j’ai réduit la facture à environ 1/10 de ce que je payais pour des solutions cloud managées, tout en conservant la même haute disponibilité et avec une latence plus faible. L’augmentation de la latence de queue due aux noisy neighbors sur les VPS faisait aussi partie des raisons
Avant, je dépensais énormément pour ce genre d’outils, mais après 4 mois en production, seules de petites mises à jour ont été nécessaires
Le déploiement est vraiment simple. Ni Docker ni Kubernetes, juste des services systemd et des binaires compilés sur la machine de dev puis déployés
Je payais aussi pour des services comme MaxMind ou IPData, mais j’ai créé mon propre service de géolocalisation IP, et dans les tests il a mieux performé que la plupart des solutions existantes
Ça a commencé comme un remplacement d’Uptime Robot, puis j’ai pris confiance et j’ai remplacé PagerDuty. Ensuite, j’ai remplacé Intercom
Enfin, on entend toujours dire qu’il ne faut pas développer soi-même la « stack de paiement », mais je me suis dit YOLO et j’ai décidé de faire moi-même cette erreur. J’ai étudié les solutions de paiement existantes, puis j’ai développé et déployé la mienne, et jusqu’ici il n’y a eu absolument aucun problème
J’utilise Caddy en frontal
Je me suis rendu compte que, parmi les fonctions fournies par la plupart des produits SaaS, je n’en utilisais en réalité que 1 à 5 %, et que les fonctions dont j’avais vraiment besoin étaient de plus en plus enfouies dans ces plateformes « enterprise-grade », ce qui compliquait les workflows
Je ne montrerai pas les produits commerciaux, parce que mes partenaires et clients n’aimeraient sans doute pas voir à quel point je fais ça à bas coût, mais moi j’appelle ça être débrouillard
Je peux montrer l’app gratuite. Elle a été lancée récemment et compte plus de 20 000 utilisateurs : https://macrocodex.app/
Cette app n’utilise que le clone de Zendesk. L’email est géré via le routage Cloudflare, donc le coût d’exploitation est quasiment nul
Il y a un vrai fossé entre un fichier et une base de données multi-partitions. Faire tourner une base de données dans un conteneur pour de la vraie prod, ce n’est pas mon style
À mon avis, beaucoup d’ETL peuvent être traités en local sans faire entrer une base de données enterprise dans l’équation. Dans ces cas-là, DuckDB est 5 à 10 fois meilleur que SQLite, et bien plus simple et rapide à mettre en place qu’une base Postgres dédiée
Pour du scripting généraliste, il n’y a pas photo entre un script awk de 20 lignes et un équivalent SQL basé sur DuckDB, bien plus propre, robuste et maintenable
J’espère que MotherDuck n’aura pas à faire du pump-and-dump en vue d’une IPO. Ce serait triste de perdre cet outil à cause d’une cupidité d’entreprise trop banale
L’histoire du script awk de 20 lignes est amusante. Hier, à l’Ubuntu Summit, j’ai défendu pratiquement le même point de vue. À partir d’un certain niveau, écrire des scripts shell avec GNU coreutils devient irréaliste, et les scripts SQL DuckDB passent bien mieux à l’échelle en termes de complexité, de maintenabilité et, souvent, de performance aussi. Les slides sont ici : https://blobs.duckdb.org/slides/duckdb-ubuntu-summit-2026.pd... pages 32 à 36
Par ailleurs, MotherDuck développe un DBaaS propriétaire construit au-dessus de DuckDB. Ils construisent sur DuckDB, et on se connecte à MotherDuck avec DuckDB, mais c’est une entreprise distincte financée par des VC et basée à Seattle
DuckDB est développé par DuckLabs, une société bootstrapée d’Amsterdam, donc financée par ses revenus. La propriété intellectuelle du projet appartient à une troisième entité, la fondation néerlandaise à but non lucratif DuckDB Foundation. Pour plus de détails, voir https://duckdb.org/faq#how-are-duckdb-the-duckdb-foundation-...
J’ai créé une bibliothèque qui permet de mettre à jour simultanément en toute sécurité une base SQLite stockée sur S3[0]
Elle fonctionne de manière assez efficace et sûre grâce à l’extension SQLite sessions, peu connue, et à un compare-and-swap S3 sur un petit fichier de métadonnées. Je l’utilise avec plaisir dans plusieurs petits projets où j’ai besoin d’une base persistante pour des fonctions Lambda, sans vouloir payer le coût d’une instance de base de données complète
[0]: https://github.com/psanford/s3db
SQLite offre des performances étonnamment bonnes, même comparé à Postgres, dans une application mono-nœud
Postgres consomme beaucoup plus de mémoire, et les entrées/sorties doivent passer par de la communication inter-processus. SQLite, lui, permet de tout garder dans le processus via un pool de connexions partagé
Je teste plusieurs moteurs de stockage pour un harness d’agents ; avec SQLite, on pouvait monter jusqu’à 7 500 sessions concurrentes sur un seul vCPU, alors que Postgres plantait ou épuisait les connexions
[0] https://github.com/impalasys/talon/pull/23#issuecomment-4577...
Dès qu’on sort du thread courant, c’est une partie perdue en termes de latence. Si on n’impose pas de communication inter-threads, SQLite peut fonctionner à l’échelle de la microseconde
Dans un contexte mono-nœud, Postgres est excessif. On ne devrait pas s’attendre à ce qu’il rivalise avec SQLite
C’est un peu comme benchmarker un HashMap presque en mémoire vive contre Redis, puis s’étonner que le HashMap donne de bons résultats dans des conditions idéales
Après avoir lu parler de SQLite pendant des années, je l’ai essayé sur un projet perso, et venant de Postgres, j’ai été choqué par la pauvreté du système de types
C’est vraiment inférieur, et je ne comprends pas pourquoi il reçoit autant d’éloges
https://sqlite.org/datatype3.html
https://www.postgresql.org/docs/current/datatype.html
La gestion des dates/heures donne l’impression d’utiliser une base de données vieille de 30 ans, et rien n’est réellement imposé à l’insertion. Il faut que quelqu’un m’explique pourquoi autant de gens aiment ça
PRAGMA journal_mode = WAL
PRAGMA foreign_keys = ON
Something non-null
PRAGMA busy_timeout = 1000This is fine for most applications, but see the manual
PRAGMA synchronous = NORMALIf you use it as a file format
PRAGMA trusted_schema = OFFSelon le binding, d’autres options peuvent être nécessaires. Par exemple, une application Python ne devrait pas utiliser les valeurs par défaut du module sqlite3. Ces valeurs par défaut sont tout simplement mauvaises. Avant la 3.12, il n’y avait même pas d’alternative autre que d’utiliser un binding hors de la bibliothèque standard : https://docs.python.org/3/library/sqlite3.html#transaction-c...
Il faut aussi utiliser les strict tables. https://www.sqlite.org/stricttables.html
On peut aussi utiliser des contraintes CHECK, même si l’ergonomie laisse à désirer. Par exemple, c’est possible avec la gestion intégrée des dates de SQLite, mais c’est maladroit :
CHECK (
date(my_date_col) IS NOT NULL
AND my_date_col = date(my_date_col)
)
Le
IS NOT NULLest nécessaire parce quedaterenvoieNULLpour les dates invalides. L’autre vérification est nécessaire parce qu’elle accepte aussi les jours juliens, doncdate('2026')devient un moment quelconque en 4707 av. J.-C.Je suis d’accord pour dire que c’était décevant, surtout avant les strict tables
Il faut regarder DuckDB. C’est proche d’un SQLite avec de vrais types. En revanche, c’est de l’OLAP, c’est-à-dire array of structs, et non de l’OLTP, c’est-à-dire struct of arrays, donc ses performances peuvent être moins bonnes que SQLite sur les charges classiques de SQLite. En pratique, pour une application qui hésite entre les deux, il n’y aura probablement pas une énorme différence
Après avoir utilisé plusieurs gros clusters Postgres, je suis passé à SQLite, et un service avec un nombre d’utilisateurs actifs mensuels à 7 chiffres repose entièrement sur des durable objects SQLite
Il faut penser les schémas d’accès différemment, mais les avantages en valaient largement la peine
C’est une bonne manière de poser le problème. Si le principal enjeu est de stocker durablement l’état d’un workflow, de pouvoir l’inspecter et de le restaurer facilement, alors SQLite suffit souvent
J’ai hâte de voir la prochaine itération de cette idée : « un workflow durable n’a besoin que d’un log »
Une raison pour laquelle les solutions du type « un log suffit » peuvent échouer, c’est quand des logs non fiables deviennent un vecteur d’injection[1]
Il faut vérifier le SBOM, sans oublier d’y inclure le pipeline CI/CD[2]
[1] https://news.ycombinator.com/item?id=48315440
[2] https://github.com/jqwik-team/jqwik/issues/708#issuecomment-...
Plus sérieusement, être expert, c’est utiliser l’outil adapté au travail