Sauvegarde et restauration
English · Type : procédure · Public : administrateur · Contexte : Reality Bridge · Statut : prête · S'applique depuis : 4.2.5
Le Reality Bridge, profil
local(SQLite) · contrat : stable · vérifié par la CI (matrice de support de la 4.4.0, 2026-10-23) : Node 22.13+ avec node:sqlite, sous Ubuntu ; Chromium et WebKit de bout en bout · vérifications automatiques : jobsreality,reality-xcheck; plan de CIreality; 2 fichiers de tests · passes humaines : aucune · limites connues :bridge-backup-digest-not-signature,bridge-backup-bounds,bridge-replace-store-two-transactions,bridge-leases-older-bridgesLe Reality Bridge, profil
distributed(Postgres) · contrat : expérimental · vérifié par la CI (matrice de support de la 4.4.0, 2026-10-23) : Postgres 16 en CI ; Le profil de qualification : HTTPS, trois instances (ops/qualify/) · vérifications automatiques : jobsbridge-postgres,deployment-smoke; plan de CIreality; 1 fichier de tests · passes humaines :bridge-postgres-httpspas faite (#77) · limites connues :bridge-backup-digest-not-signature,bridge-backup-bounds,bridge-replace-store-two-transactions,bridge-leases-older-bridges
Comment sauvegarder le stockage d’un Reality Bridge dans un seul fichier, le restaurer tout ou rien, et remettre un
Bridge en route après la perte d’une instance ou de sa base. Il s’agit de la sauvegarde du Bridge
(npm run bridge -- backup), pas de celle du Studio hébergé (studio-server backup,
Sauvegardes sur Clever Cloud).
Ce que vous obtenez
Un fichier de sauvegarde du stockage entier, pris en un seul instantané, avec une empreinte qui détecte un fichier modifié ou tronqué par accident ; et, le jour où il le faut, un stockage restauré depuis ce fichier en une seule transaction, vérifié avant et après sa validation, dans un mode que vous nommez.
Contexte et versions
- Un Bridge sur un stockage SQL (SQLite ou Postgres). Le journal JSON-lines peut être sauvegardé, mais pas restauré : migrez-le d’abord vers SQLite (Stockages).
- À partir de la 4.1.20 : le schéma 4 des sauvegardes (ADR 0023), les deux modes de restauration et les baux de
maintenance. Le schéma 3 est venu avec la 4.1.19 (ADR 0021). Une restauration lit les schémas 1 à 4. Cette page
s’applique à partir de la 4.2.5 (les noms
quest-n-click-bridge). - Vérifié sur :
backup,restore --mode=merge(refusé, puis avec--force) etrestore --mode=replace-storeont été lancés le 23 octobre 2026 sur un stockage SQLite du jeusignals(un tenant, un signal), macOS, Node 22.14, moteur 4.4.0. Un gros stockage ou un stockage Postgres n’ont pas été rejoués pour cette page ; les répétitions en CI sont nommées dans les Références.
Prérequis
- Le dossier du Bridge (
--dir, avecconfig.json) et l’accès à son stockage (le fichier SQLite, ou l’URL Postgres dansBRIDGE_STOREouBRIDGE_STORE_FILE). - De la mémoire pour la taille du fichier, environ 10 Mo par Mio sauvegardé et 20 Mo par Mio restauré (la mesure plus bas).
- Pour une restauration : toutes les instances du Bridge sur ce stockage arrêtées, et toute instance antérieure à la 4.1.20 arrêtée avant la première restauration (elles ne prennent pas de bail de maintenance).
Où lancer les commandes
Sur une machine qui atteint le stockage, avec le dossier du Bridge : la machine du Bridge, ou une machine avec plus de
mémoire (une restauration n’a besoin que d’atteindre le stockage). npm run bridge -- … dans le dépôt du moteur ;
npx quest-n-click-bridge … avec le paquet autonome.
Étapes
Sauvegardez le stockage :
# sur la machine du Bridge, dans le dépôt du moteur npm run bridge -- backup --out=bridge-2026-10-23.jsonElle affiche
✔ 1 tenant(s), 1 signal(s), 0 run(s), 0 daily record(s) backed up to …/bridge-2026-10-23.json (schema 4, one snapshot, sha256 1edef3c0f48b…). Le stockage entier est lu dans une seule transaction en lecture seule : tenants, runs, enregistrements du jour et quota des speedruns. Le fichier est en mode 600, écrit dans un fichier temporaire puis renommé. Il contient les empreintes des capacités, jamais une capacité ni une clé.Son enveloppe donne le backend, les versions du Bridge et du schéma SQL, ce qu’elle contient (
completeness:whole-storepour un stockage SQL,tenants-onlypour le journal ou la mémoire), le début et la fin, les comptes par famille, et un SHA-256 de l’ensemble (scope: envelope).
Limite ·
bridge-backup-digest-not-signatureL’empreinte est un contrôle d’intégrité contre un fichier modifié ou tronqué par accident, pas une signature : quiconque peut modifier le fichier peut la recalculer. Gardez les sauvegardes là où vous seul pouvez écrire.
Limite ·
bridge-backup-boundsUn stockage au-delà de--max-rows(2 000 000) ou un fichier au-delà de--max-bytes(256 Mio) est refusé et aucun fichier n’est écrit. Au-delà de quelques centaines de Mio, utilisez les outils de la base elle-même (pg_dump, les instantanés du fournisseur, une copie du fichier SQLite Bridge arrêté).
- Pour restaurer, arrêtez d’abord chaque
servesur ce stockage. Depuis la 4.1.20, le stockage refuse une restauration tant que quelque chose tient un bail vivant, en nommant qui le tient et jusqu’à quand ; une restauration ne tourne jamais à côté d’écrivains vivants.
Restaurez avec
--mode=merge: dans un stockage vide, ou avec--forcepar-dessus les tenants que contient le fichier.# sur une machine qui atteint le stockage, dans le dépôt du moteur npm run bridge -- restore --from=bridge-2026-10-23.json --mode=merge # dans un stockage vide, sinon refusé npm run bridge -- restore --from=bridge-2026-10-23.json --mode=merge --force # les tenants du fichier remplacés, les autres gardésUn conflit (un tenant, un run ou un quota de ses tenants, une clé du jour) la refuse sans
--force:✖ the store already holds tenant(s) default: restore into an empty store, or --force; nothing restored. Avec--force, les familles du fichier remplacent ce avec quoi elles entrent en conflit, et ce dont le fichier ne parle pas reste (un autre tenant, une autre clé du jour). Tout schéma, de 1 à 4.
Ou restaurez avec
--mode=replace-store: le stockage devient le fichier.# sur une machine qui atteint le stockage, dans le dépôt du moteur npm run bridge -- restore --from=bridge-2026-10-23.json --mode=replace-store --yes-replace-store --safety-out=before-restore.jsonToutes les tables sauf celles de contrôle (
schema_migrations) sont vidées dans la même transaction, puis le fichier est écrit et relu, rien de plus n’est gardé. Ce mode n’accepte qu’une sauvegarde de schéma 4 d’un stockage SQL entier, au schéma SQL de ce stockage. D’abord, une sauvegarde du stockage remplacé est écrite dans--safety-out, un chemin qui ne doit pas exister (pas de lien non plus), relue et vérifiée ; si cela échoue, rien n’est supprimé. Son chemin est rappelé dans chaque issue.
Limite ·
bridge-replace-store-two-transactionsLa sauvegarde de sécurité et le remplacement sont deux transactions : arrêtez tout écrivain entre les deux (le bail de maintenance les refuse à partir de la 4.1.20). Le fichier de sécurité est écrit par un lien physique, qui ne remplace jamais un nom : donnez-lui un chemin sur un système de fichiers qui les accepte (ni FAT ni exFAT).
Vérifiez le stockage, puis relancez le Bridge :
# dans le dépôt du moteur npm run bridge -- doctor
Garantie ·
bridge-restore-names-its-mode· référencée · exécutée suraff6caab7514· portée vérifiée par son auteur (IA), pas relue Sans--mode, ou avec--forceseul,restores’arrête avec le code de sortie 2, et l’usage nomme les deux modes.
Garantie ·
bridge-restore-refused-while-serving· référencée · portée vérifiée par son auteur (IA), pas relue Tant qu’un Bridge sert le stockage, une restauration est refusée et dit que rien n’a été restauré. Une fois le Bridge arrêté, elle restaure.
Résultat attendu, et comment le vérifier
restore se termine avec le code 0 et une ligne : ✔ 1 tenant(s), 0 run(s), 0 daily record(s), 0 quota row(s) restored from <date> (schema 4, merge), checked before and after the commit (avec replace-store, suivie de (the store before: <fichier de sécurité>)). Le fichier a été lu de façon bornée et vérifié en entier avant l’ouverture du
stockage (schémas 1 à 4 ; chaque ligne, les doublons, les relations, les comptes et l’empreinte de la charge du schéma
3, l’empreinte de l’enveloppe du schéma 4, les dates, la version et la complétude), écrit dans une transaction, relu
et comparé avant la validation, puis audité après. doctor liste ensuite les joueurs et les signaux de chaque tenant,
sans trou.
Erreurs fréquentes
| Message ou code de sortie | Cause | Correction |
|---|---|---|
code 2, say the mode: --mode=merge … --mode=replace-store …; nothing restored | Pas de --mode | Nommer le mode |
the store already holds tenant(s) …: restore into an empty store, or --force; nothing restored | Un conflit en merge | Un nouveau stockage, ou --force |
replace-store needs a schema 4 backup of a whole SQL store (…) | Un fichier plus ancien, ou venu du journal (tenants-only) | --mode=merge, ou une nouvelle sauvegarde |
the backup comes from a store at schema N, newer than this one (M): upgrade the Bridge | Le moteur est plus ancien que la sauvegarde | Mettre le Bridge à jour |
the JSON-lines journal cannot be restored all or nothing: migrate it to SQLite first … | Le stockage est le journal | migrate --from=jsonl --to=sqlite, puis restaurer avec --store=sqlite |
the backup would be N bytes, more than M (--max-bytes=): no file written | Un stockage trop gros pour un fichier | Les outils de la base elle-même |
Un refus qui nomme le détenteur du bail, ; nothing restored | Un Bridge sert encore le stockage | L’arrêter |
code 3, P0: the restore committed but … | Une différence trouvée après la validation | Arrêter toutes les instances, garder ce stockage pour examen ; un écrivain pendant la restauration peut l’expliquer |
code 3, the commit's answer was lost … | La connexion est tombée à la validation | doctor, et une sauvegarde, pour voir de quel côté c’est tombé |
Fichiers ou données modifiés
backup: le fichier--outseulement (mode 600). Elle lit le stockage.restore --mode=merge: les tenants, runs, enregistrements du jour et quotas que contient le fichier (avec--force, ceux avec lesquels il entre en conflit sont remplacés). Le reste du stockage reste.restore --mode=replace-store: toutes les tables saufschema_migrations; et le fichier--safety-out, écrit en premier.
Reprise ou retour en arrière
- Une restauration ratée dit « nothing restored » et laisse le stockage tel qu’il était (une seule transaction).
- Après un
replace-store, le chemin du retour est son fichier de sécurité :restore --from=<fichier de sécurité> --mode=replace-store …avec un nouveau--safety-out. - Une instance tuée ou plantée : en lancer une autre ; rien n’est perdu (une transaction est validée ou absente ;
tests/bridge-fanout.test.tsen tue une sur trois pendant 1 000 propositions). - La base perdue : restaurer la dernière sauvegarde dans une nouvelle, puis
doctor. Les connecteurs renvoient ce qu’ils ont envoyé depuis (leurdedupeKeyrend l’envoi idempotent), et les joueurs gardent leurs curseurs. - Un journal qui ne démarre pas :
doctornomme la ligne. - Une clé ou une racine Biscuit compromise, ou l’hôte d’une instance : Sécurité.
Santé et mesures
GET /livez: le processus répond.GET /readyz: le stockage répond (503 sinon).GET /healthz: les deux, avec les tenants, le type de stockage et les flux ouverts. Sans jeton, sans donnée d’un tenant.- Mesures : acceptations, doublons, refus par code, accusés de réception, nouvelles tentatives du stockage,
quarantaine, flux refusés, l’arriéré et la latence d’une proposition. Toujours gardées dans le processus ; par l’API
de métriques d’OpenTelemetry quand
@opentelemetry/apiest installé à côté du Bridge, exportées en OTLP quandOTEL_EXPORTER_OTLP_ENDPOINTest défini et@opentelemetry/sdk-nodeinstallé. Attributs : le tenant et un code, jamais un joueur ni une charge. - Une ligne gardée qui ne se vérifie plus est mise en quarantaine, jamais livrée, et
doctorla liste.
Mémoire : dimensionner la machine à la sauvegarde
backup, tenant export et restore tiennent le fichier entier en mémoire, lu et canonique ; une restauration le
tient deux fois (le fichier, puis le stockage relu pour comparer).
Mesure ·
bridge-backup-memoryPic de mémoire (RSS) du Bridge de l’archive, pour environ 72 Mo au repos : une sauvegarde de 64 Mio a pris 0,6 Go à l’export, 1,4 Go à la restauration sur SQLite et 1,3 Go sur Postgres ; 128 Mio, 1,1 à 1,3 Go, 2,7 Go et 2,4 Go ; 256 Mio, 2,1 à 2,2 Go, 3,1 Go et 3,7 Go. À lire comme environ 10 Mo de mémoire par Mio de fichier pour une sauvegarde, 20 Mo pour une restauration : une observation, pas une promesse pour votre machine.
- date: 2026-10-13
- version: 4.1.20
- volume: sauvegardes de 64, 128 et 256 Mio, sur SQLite et sur Postgres
- conditions: le job
backup-memorydu candidat (tools/backup-memory.ts), un runner Linux de GitHub, le Bridge de l’archive du candidat ; une mesure par taille et par stockage- source: REALITY-OPS.md, "Health, measures, backups"
Dans un conteneur de 512 Mio, une restauration tient jusqu’à environ 20 Mio de sauvegarde. Lancez une plus grosse
depuis une machine qui a la mémoire, ou abaissez --max-bytes et --max-rows à ce que la machine tient, pour qu’un
fichier trop gros soit refusé avant d’être lu.
Les baux de maintenance (4.1.20)
À partir du schéma 5 (migration 0005), chaque écrivain tient un bail dans le stockage lui-même (ADR 0023) :
serveet chaque commande qui écrit (migrate,tenant delete,backupettenant export, qui montent le schéma) tiennent un bailserving, côte à côte.restore, etmigrate --schema=Nvers le bas, prennent le bailexclusive. Ils sont refusés, en nommant qui tient le stockage et jusqu’à quand, tant que quoi que ce soit d’autre tient un bail vivant : aussitôt sur SQLite ; sur Postgres après le--lock-timeoutdu verrou consultatif au plus (30 s par défaut, jamais attendu plus longtemps).- Un bail expiré (un processus tué) est supprimé, jamais gênant. Toutes les heures sont celles de la base.
- Un
servequi perd son bail (non renouvelé, ou la connexion de son verrou tombée) retient ses écritures, qui répondent 503, et échoue à/readyzjusqu’à ce qu’il reprenne un bail ; de même pour un processus qui se fige au-delà des deux tiers de son bail, sur sa propre horloge. Une restauration qui perd son bail avant la validation est annulée.
Limite ·
bridge-leases-older-bridgesUn Bridge antérieur à la 4.1.20 ne prend pas de bail : arrêtez toute instance plus ancienne avant la première restauration.migrate --schema=Nen dessous de 5 supprime la table des baux dès sa première étape : arrêtez tout écrivain pour cela.
Les lignes d’un seul tenant
tenant export --tenant=<id> [--out=<fichier>] écrit les lignes d’un tenant, dans chaque table (sur la sortie
standard sans --out) ; tenant delete --tenant=<id> --yes les supprime. Sans --yes, rien n’est supprimé. La
sauvegarde est logique, portable et bornée ; pour un gros déploiement, pg_dump ou les instantanés du fournisseur
restent la sauvegarde de la base elle-même.
Références
- Le code :
bridge/src/backup/,bridge/src/cli-store.ts,bridge/src/maintenance.ts. - La conception : ADR 0021 (un instantané, tout ou rien), ADR 0023 (la complétude, les modes, les baux).
- Répété par
tests/bridge-backup.test.ts,tests/bridge-backup-v4.test.ts,tests/bridge-maintenance.test.tsettests/bridge-ops.test.ts; la topologie entière détruite et restaurée parnpm run ops:qualify(Le déploiement de référence). - La ligne de commande du Bridge · Dépannage.