quest'n'click 4.5.0 · r1

Construite pour quest'n'click 4.5.0, révision r1. Si elle est publiée, et laquelle est la courante, est dit par publication.json.

Sauvegardes

English · Type : procédure + référence · Public : administrateur · Contexte : Studio hébergé · Statut : prête · S'applique depuis : 4.2.3

Le Studio Server (Studio d'équipe hébergé) · contrat : expérimental · vérifié par la CI (matrice de support de la 4.4.0, 2026-10-23) : Postgres, S3 et Keycloak en CI ; Chromium et Firefox (job studio-hosted) ; WebKit sous macOS, à la main seulement · vérifications automatiques : jobs studio-hosted, studio-install-smoke ; plan de CI studioHosted ; 3 fichiers de tests · passes humaines : studio-hosted pas faite (#149), studio-collab pas faite (#150), studio-preview pas faite (#166), studio-assets-hosted pas faite (#167), studio-mcp-remote pas faite (#196), studio-oidc-generic pas faite (#197) · limites connues : aucune listée sur cette page

Un Studio hébergé protège son jeu deux fois : le journal de chaque modification confirmée est expédié vers le bucket à mesure qu’il s’écrit, et une sauvegarde quotidienne des tables du projet est écrite dans le même bucket. Cette page met en place la sauvegarde quotidienne, dit ce qu’une sauvegarde contient et ne contient pas, et combien de temps les sauvegardes sont gardées.

Ce que vous obtenez

Une sauvegarde backups/<date>-r<révision>.json dans le bucket de l’instance chaque jour à 03:17 UTC, les 14 plus récentes gardées (ou STUDIO_BACKUP_KEEP), sa ligne "event":"backup" dans les journaux de l’application studio, et la façon d’en faire une à la main avant une montée de version. Avec le journal expédié depuis, une sauvegarde restaure le jeu jusqu’à sa dernière révision expédiée (exercice de restauration).

Contexte et versions

Prérequis

Où lancer les commandes

Étapes

  1. Activez la sauvegarde quotidienne, sur l’application studio seulement, jamais sur le worker :

    # sur votre machine, dans le dépôt du moteur
    clever env set --alias my-game-studio STUDIO_BACKUP_CRON 1
    clever env set --alias my-game-studio STUDIO_BACKUP_KEEP 14      # facultatif ; 14 en son absence
    

    Le clevercloud/cron.json du dépôt lance ops/studio/backup-cron.sh chaque jour à 03:17 UTC. Clever Cloud installe les tâches d’un dépôt sur chaque application et chaque instance déployée depuis lui : le script ne fait donc rien si l’application ne définit pas STUDIO_BACKUP_CRON=1, et rien sur une autre instance que la numéro 0 (INSTANCE_NUMBER). Il lance alors npm run -s studio-server -- backup --to-bucket --keep "${STUDIO_BACKUP_KEEP:-14}". Un changement de variable s’applique au déploiement ou au redémarrage suivant.

  1. Le lendemain matin, trouvez la ligne de la sauvegarde dans les journaux (clever logs --alias my-game-studio --since 12h, arrêté par son numéro de processus : sinon il continue de suivre), ou lancez le script à la main pour la voir tout de suite :

    # dans un shell sur l'application studio (clever ssh --alias my-game-studio)
    cd "$APP_HOME" && ops/studio/backup-cron.sh
    

    Sa ligne est {"event":"backup","key":"backups/2026-10-19T19-38-41Z-r63.json","revision":63,"digest":"…","removed":[…]}.

Mesure · backup-time Le script lancé à la main sur l’instance 0 : 1,87 s, démarrage de tsx compris, pour une sauvegarde de 253 958 octets à la révision 63. Un second passage aussitôt avec STUDIO_BACKUP_KEEP=3 a supprimé la seule sauvegarde au-delà de 3, en 2,07 s.

  • date: 2026-10-19
  • version: 4.2.2
  • volume: le jeu de démo à la révision 63 (500 fichiers) ; des sauvegardes de 170 746 octets (r1) à 253 958 octets (r63)
  • conditions: phase B du déploiement de référence, moteur au commit c66fbf56 avant le tag 4.2.3 (package.json disait 4.2.2) ; application studio XS, PostgreSQL DEV, Cellar S, région par ; un échantillon chacun
  • source: QUALIF-4.2.3-REFERENCE.md §3
  1. Avant une montée de version, ou toute opération risquée, faites-en une à la main et notez sa révision. Sans --keep, rien n’est supprimé :

    # dans un shell sur l'application studio (clever ssh --alias my-game-studio)
    cd "$APP_HOME" && npm run -s studio-server -- backup --to-bucket
    

    backup <fichier> écrit la même sauvegarde dans un nouveau fichier (mode 0600 ; un fichier existant est refusé), sur le disque de l’instance, qui ne survit pas à un redémarrage : sur Clever Cloud, préférez le bucket.

  1. Copiez vous-même le bucket hors de Cellar, avec un outil S3, vers un stockage où seuls les opérateurs écrivent : backups/, mais aussi sha256/ (le contenu des fichiers) et journal/ (les opérations expédiées). Une sauvegarde nomme ses blobs sans les contenir, et une restauration refuse une sauvegarde dont des blobs manquent : une copie de backups/ seule ne restaure rien. Le bucket contient les trois ensemble : une sauvegarde survit à la perte de la base, pas à celle du bucket ou de ses identifiants.

Garantie · backup-keep-own-only · référencée · exécutée sur aff6caab7514 · portée vérifiée par son auteur (IA), pas relue --keep n ne supprime que les sauvegardes que cette commande a écrites (les clés backups/<date>-r<révision>.json) au-delà des n plus récentes, celle qui vient d’être écrite comptant pour l’une d’elles : jamais un autre objet du bucket, ni un fichier d’un autre nom sous backups/.

Ce qu’une sauvegarde contient, et ce qu’elle ne contient pas

ContientNe contient pas
Les tables du projet, lues en un seul instantané en lecture seule : la tête (studio_files, studio_meta), les opérations confirmées (studio_ops), les membres, utilisateurs, invitations, le journal d’audit, l’annulation personnelle, les verdicts de santé, les prévisualisations, les builds publiés, les ensembles préparés, les commentairesLe contenu des fichiers : elle liste les blobs qu’elle nomme, par leur hash ; ils restent dans le bucket
Un condensé (sha256 de ses tables), vérifié à la restauration : une sauvegarde altérée ou tronquée est refuséeLes sessions et les connexions en cours : une restauration déconnecte tout le monde
La version du schéma où elle a été faite : une restauration demande la mêmeLes baux (celui de l’écrivain, celui du service, ceux des pans) : personne ne tient de pan après une restauration
Les opérations en cours ou abandonnées à l’instantané ; les réponses gardées pour la nouvelle tentative d’un client (7 jours) ; les tickets et sessions de l’origine du jeu

Une sauvegarde est une entrée de confiance, comme les identifiants de la base : elle peut ajouter des owners. Son condensé dit qu’elle est entière, pas qui l’a faite : gardez-la là où seuls les opérateurs écrivent.

Le journal expédié vers le bucket

Chaque opération confirmée est copiée dans le bucket, dans l’ordre, en segment immuable (journal/<époque>/<ligne>/<rev>.json ; les contenus sont déjà des blobs). Un échec est consigné ship-failed et retenté sous 30 s. /readyz donne rpoMs, l’âge de la plus ancienne opération pas encore expédiée (0 quand tout l’est) : la cible est une minute (D42), surveillée, jamais promise (RPO et RTO). La ligne vaut 0, puis une nouvelle après chaque restauration : les révisions qu’une instance restaurée réécrit n’écrasent jamais les segments de la chronologie qu’elle a quittée. Faites une nouvelle sauvegarde après une restauration : les suivantes rejouent sur la nouvelle ligne.

Ce que fait une restauration

La procédure, c’est l’exercice de restauration ; voici ce que fait la commande, en bref. Elle ne restaure qu’une instance hébergée, dans une base vide (un nouvel add-on PostgreSQL, le même bucket) : npm run studio-server -- restore <fichier> --replay --config <fichier> vérifie le condensé, les tables et les colonnes, et que chaque blob de la tête et du journal est dans le bucket (une prévisualisation, un build ou un ensemble préparé dont les blobs ont été ramassés depuis est laissé de côté et compté dans dropped) ; écrit les lignes ; puis rejoue le journal expédié depuis la sauvegarde. Chaque opération rejouée doit continuer la tête (sa révision, le contenu précédent de chaque fichier, ses blobs) ; le rejeu s’arrête à la première qui ne le fait pas (stopped : gap, not-the-head, blob-missing…). S’il échoue en cours de route, le serveur refuse de démarrer jusqu’à ce que npm run studio-server -- replay --config <fichier> le reprenne. Démarrez ensuite le serveur : son dossier est refait depuis la tête. Les opérations rejouées ne gardent pas leur réponse : un client qui en retente une reçoit null. Faites une nouvelle sauvegarde après une restauration : les suivantes rejouent sur la nouvelle ligne.

Depuis les archives de la release

Les archives de la release ne portent pas ops/studio/backup-cron.sh. Copiez-le dans le dépôt de votre application en remplaçant sa dernière ligne par :

# la dernière ligne de backup-cron.sh, dans le dépôt de votre application (lancée par la tâche de Clever sur l'application studio)
exec npx quest-n-click-studio-server backup --to-bucket --keep "${STUDIO_BACKUP_KEEP:-14}"

rendez-le exécutable, et pointez votre propre clevercloud/cron.json dessus : ["17 3 * * * $ROOT/backup-cron.sh"]. Clever Cloud lance une tâche sans environnement à moins que son script commence par #!/bin/bash -l (la première ligne du script), et avec des chemins absolus seulement ($ROOT est le dossier de l’application).

Résultat attendu, et comment le vérifier

Erreurs fréquentes

SymptômeCauseCorrection
Pas de ligne "event":"backup" un matinSTUDIO_BACKUP_CRON n’est pas 1, pas de redéploiement depuis, ou pas d’INSTANCE_NUMBER=0Dépannage
backup --to-bucket writes to the instance's bucket: blobs.kind is s3Une configuration localeLancez-la sur l’application studio
backup: --keep is the number of backups kept (1 or more)STUDIO_BACKUP_KEEP vaut 0, est négatif ou n’est pas un entierUn entier à partir de 1
backup: a new file is required (or --to-bucket [--keep n])backup sans fichier, ou avec un fichier existantUn nouveau nom de fichier, ou --to-bucket
Deux sauvegardes à la même minuteUn redéploiement à chevauchement à 03:17 : deux instances numérotées 0 un instantSans conséquence

Fichiers ou données modifiés

Des objets sous backups/ dans le bucket ; avec --keep, les plus anciens des siens supprimés. Rien dans la base.

Reprise ou retour arrière

Une sauvegarde supprimée par --keep est perdue, sauf si vous l’avez copiée ailleurs (étape 4). Restaurer une sauvegarde, c’est l’exercice de restauration, dans une nouvelle base.

Ramasser les blobs inutilisés

npm run studio-server -- gc liste les blobs qu’aucune ligne ne nomme (plus vieux d’un jour) et le staging du worker de plus d’une heure ; --delete les supprime. Un blob stocké à nouveau reçoit une nouvelle date : une écriture qui nomme un vieux blob est couverte par le jour de grâce. Les blobs de la tête et du journal ne sont jamais ramassés (le journal garde chaque opération) ; une sauvegarde plus ancienne restaurée après un ramassage ne perd que les prévisualisations, builds et ensembles préparés ramassés (comptés dans dropped). Ne lancez jamais gc --delete contre la base d’un exercice : il supprimerait des blobs que la production nomme encore.

Références


Modifier la source de cette page · Signaler une erreur