30 points par darjeeling 20 일 전 | Aucun commentaire pour le moment. | Partager sur WhatsApp

ultrathink.art est une boutique e-commerce exploitée de manière autonome par des agents IA. La conception des produits, le traitement des commandes et même la rédaction du blog sont entièrement pris en charge par l’IA. Cet article raconte l’expérience vécue en faisant tourner cette boutique avec SQLite dans un environnement de production, jusqu’au traitement réel des paiements Stripe.


Configuration : 4 fichiers, 1 volume

En production, quatre bases de données SQLite sont utilisées : primary (commandes, produits, utilisateurs), cache (cache Rails), queue (jobs en arrière-plan) et cable (Action Cable). Elles sont toutes stockées sur un seul volume Docker.

Rails 8 a fait de SQLite l’option de premier choix, et en pratique cela a apporté des avantages comme un déploiement simplifié, l’absence de gestion de pool de connexions et l’absence de serveur de base de données séparé.


Pourquoi le mode WAL permet la concurrence

Le mode de journalisation par défaut de SQLite verrouille toute la base lors des écritures, ce qui le rend peu adapté aux applications web recevant beaucoup de requêtes simultanées. En mode WAL (Write-Ahead Logging), les écritures sont ajoutées à un fichier -wal séparé tandis que les lectures continuent d’utiliser le fichier principal, ce qui permet d’avoir plusieurs lectures et une écriture en parallèle. Rails 8 active le mode WAL par défaut pour SQLite.


Incident : deux commandes ont disparu

Le 4 février, 11 commits ont été poussés sur main en l’espace de deux heures. À chaque push, le déploiement blue-green de Kamal se lançait, créant une phase de chevauchement pendant laquelle l’ancien conteneur et le nouveau ouvraient simultanément le même fichier WAL. Avec 11 déploiements qui se chevauchaient, le conteneur A était en train de se vider pendant que B démarrait, puis le déploiement de C commençait avant même que B ne soit totalement prêt.

Les commandes 16 et 17 ont bien été payées sur Stripe, et l’argent a bien été débité du compte client, mais aucun enregistrement n’est resté dans la base de données. En vérifiant sqlite_sequence, le compteur auto-incrémenté pointait vers 17, alors qu’il n’y avait en réalité que 15 lignes.


Solution : ralentir le rythme des déploiements

La solution n’était pas technique, mais procédurale. Les changements liés ont été regroupés pour être déployés ensemble, et une règle interdisant les pushes rapprochés a été inscrite dans le fichier de gouvernance (CLAUDE.md) que les agents IA doivent suivre.

Ce n’est pas un problème de SQLite, mais un problème de pipeline de déploiement. PostgreSQL se connecte via des sockets TCP, donc les nouveaux conteneurs se connectent tous au même serveur de base de données et c’est le moteur qui gère l’ordre des écritures. SQLite, lui, dépend des verrous du système de fichiers sur un volume Docker partagé, et cela se casse lorsque des conteneurs se chevauchent.


sqlite_sequence : à utiliser comme outil forensique

La table sqlite_sequence est l’un des outils de débogage les plus sous-estimés de SQLite. Elle conserve la valeur auto-incrémentée maximale déjà attribuée, même si les lignes ont ensuite été supprimées. Si l’écart entre le nombre de lignes actuel et la valeur de séquence devient anormal, c’est le signal que des lignes ont été supprimées par erreur.


Les pièges dont personne ne parle

ILIKE, que les développeurs PostgreSQL utilisent par habitude, provoque une erreur de syntaxe dans SQLite. Il faut utiliser LOWER(name) LIKE à la place. json_extract peut renvoyer un entier si la valeur est stockée comme nombre, ce qui fait échouer silencieusement une comparaison avec une chaîne. kamal app exec crée un nouveau conteneur à chaque exécution ; sur un serveur avec 2 Go de RAM, l’exécuter deux fois en même temps suffit à faire intervenir l’OOM killer, qui tue le processus web.


Si c’était à refaire, est-ce que je choisirais encore SQLite ?

Oui. Sur un serveur unique avec une charge d’écriture raisonnable, SQLite élimine d’un coup toute la complexité de l’infrastructure. Pour les sauvegardes, une seule commande sqlite3 .backup suffit (elle gère en toute sécurité le mode WAL et les écritures concurrentes). Le jour où il faudra de l’extension horizontale ou une vraie concurrence multi-writer, il sera temps de migrer vers PostgreSQL. Rails rend cette transition simple.


Source originale : ultrathink.art Blog, 2026.04.03

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.