1 points par GN⁺ 4 시간 전 | 1 commentaires | Partager sur WhatsApp
  • 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

1 commentaires

 
GN⁺ 4 시간 전
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

    • On dirait que ça tourne surtout sur une seule machine
      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
    • D’après ce qu’on entend sur HN, soit on paie bien plus que prévu pour la solution managée de Temporal, soit on finit par exploiter soi-même un système très lourd, en assumant une charge opérationnelle importante
      Je ne l’ai pas fait moi-même, mais j’aimerais entendre plus de retours d’expérience concrets
    • Peux-tu donner un exemple concret de cas où SQLite est utilisé à la place de jq ou grep sur du Markdown ?
    • On dirait une pub pour Temporal :)
    • La discussion entre approche par fichiers et approche base de données est intéressante. Moi aussi j’ai fait des allers-retours avant de finir par me fixer sur une base de données
  • 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

    • La compréhension des différents types de concurrence et de la manière de répondre à ces exigences semble assez limitée. Le fait qu’il s’agisse ou non d’un serveur n’a pas tant d’importance dans cette discussion
      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
    • Il arrive souvent qu’une combinaison de SQLite et d’un frontend gérant la concurrence, par exemple un serveur net/http de 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 TPS
      Ce à 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
    • SQLite est très bien pour de nombreux usages, mais tu sembles sans doute passer l’essentiel de ton temps sur de grosses applications web qui ont besoin d’une base de données en réseau et de sharding. C’est un domaine intéressant lui aussi, mais il y en a beaucoup d’autres
      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
    • N’est-ce pas justement pour cela qu’il existe des milliards de bases de données SQLite ?
      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
    • Si les données sont naturellement shardées et que les écritures ont lieu à l’intérieur d’un seul shard, alors le parallélisme devient facile. Les requêtes sont routées vers le shard où se trouvent les données de l’utilisateur, et on y effectue localement les lectures/écritures
      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

    • J’ai créé moi-même un moniteur d’uptime ; comment gérez-vous différemment la distribution géographique ou les tests sur des connexions résidentielles ?
  • 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

    • Je m’occupe des relations développeurs chez DuckDB. Merci d’abord pour les mots sympathiques :)
      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...

    • Quand on l’utilise correctement, SQLite revient en pratique à un appel de méthode intra-processus. S’il ne reste comme obstacles que le runtime, le noyau, le système de fichiers et le stockage NVMe local, ça peut être écrasant de rapidité par rapport aux alternatives hébergées
      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
    • Si l’on part du principe que SQLite est un logiciel excellent, ne devrait-on pas justement s’attendre à ce qu’il soit performant face à Postgres dans une application mono-nœud ?
      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

    • On peut utiliser les tables STRICT : https://sqlite.org/stricttables.html
    • Oui, c’est pratiquement mon seul vrai reproche à SQLite. Un SQLite avec un système de types strict serait excellent
    • C’est la faute, et le prix, de la rétrocompatibilité. La plupart des utilisateurs de SQLite doivent exécuter quelques pragma à chaque connexion
      PRAGMA journal_mode = WAL
      PRAGMA foreign_keys = ON

      Something non-null

      PRAGMA busy_timeout = 1000

      This is fine for most applications, but see the manual

      PRAGMA synchronous = NORMAL

      If you use it as a file format

      PRAGMA trusted_schema = OFF
      Selon 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 NULL est nécessaire parce que date renvoie NULL pour les dates invalides. L’autre vérification est nécessaire parce qu’elle accepte aussi les jours juliens, donc date('2026') devient un moment quelconque en 4707 av. J.-C.
    • Parce que c’est un fichier unique
    • Il est encensé pour des choses autres que le système de types
      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 »

    • Pas besoin d’attendre, c’est déjà en train d’arriver
      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, j’accepterais volontiers l’idée que « un workflow durable n’a besoin que de S3 », et je l’utiliserais pour une application de traitement de données qui déplace des données de S3 vers S3
    • Un log seul suffit-il vraiment pour un workflow durable ? Je suis perdu. Comment persister et interroger des données imbriquées ou liées au-dessus d’un log ? Ici, par log, on parle d’Elasticsearch ou de quelque chose comme Meilisearch ?
    • Ensuite viendra « un workflow durable n’a besoin que de sockets », et à la fin « un workflow durable n’a besoin que de primitives du noyau »
      Plus sérieusement, être expert, c’est utiliser l’outil adapté au travail