As regras están na sección 7 de docs/architecture/23-ops.md e na sección 4.1 de docs/architecture/07-data.md. Este é o procedemento.
A garantía que o fai seguro
A versión R execútase correctamente tanto co esquema R como co esquema R menos un. Cada cambio do esquema divídese en expansión, transición e eliminación:
- Expansión: engade a nova columna, táboa ou índice. O código antigo ignóraos.
- Transición, durante polo menos unha versión: o código novo escribe ambas as estruturas e le a nova; unha tarefa reanudable completa as filas antigas.
- Eliminación: elimina a estrutura antiga nunha versión posterior e de forma illada.
Así, en cada momento dunha actualización gradual, os procesos antigos e novos poden compartir a mesma base de datos. Non hai migracións á inversa: unha migración que eliminou unha columna hai unha hora non pode recuperar as filas escritas durante esa hora.
A tarefa de CI schema-compat comproba esta garantía en cada versión executando as probas da versión anterior co esquema novo.
Antes de comezar
- Le as notas da versión. Se unha versión require unha xanela de mantemento, indícao xunto coa duración estimada; hai como máximo unha por versión.
- Executa a proba de restauración ou confirma que se completou correctamente para esta versión (backup-restore.md). Se falla, a actualización queda bloqueada.
- Fai unha copia base:
docker compose -f docker/compose.yaml --profile backup run --rm backup.
Docker Compose nun host
export QUIRE_RELEASE=2026.10.0 # or set it in docker/.env
docker compose -f docker/compose.yaml pull # or build
docker compose -f docker/compose.yaml run --rm migrate
docker compose -f docker/compose.yaml up -d --no-deps web content collab
docker compose -f docker/compose.yaml up -d --no-deps worker schedulerA orde é deliberada:
- Primeiro as migracións, mentres a versión antiga segue atendendo peticións. As migracións de expansión son invisibles para ela.
- Despois a capa web. Cando recibe SIGTERM, cada proceso web cambia
/readyzadraining, remata as peticións en curso nun máximo de 30 segundos, pecha as conexións mantendo unha indicación para reconectar e sae.stop_grace_periodé de 40 segundos para que Compose non corte un proceso que estea rematando correctamente. - Por último, os traballadores, para que se produza a estrutura de evento máis recente antes de que a espere o consumidor máis novo. Os traballadores deixan de buscar tarefas de inmediato e teñen 120 segundos; as tarefas que non poidan rematar poden ser recollidas noutro lugar, o que é seguro porque todas son idempotentes. O planificador transfire o liderado no seguinte ciclo.
Nun só host, Compose substitúe os contedores por quendas, polo que cada servizo ten unha interrupción breve. Para non ter ningunha interrupción, executa dous contedores da capa web detrás do teu propio proxy (cun ficheiro de substitución que engada un segundo servizo web sen porto publicado) e recréaos un por un, agardando a que cada un estea saudable antes de pasar ao seguinte.
Varios hosts ou un orquestrador
Segue a mesma orde: executa as migracións unha vez desde unha única tarefa; actualiza gradualmente a capa web con un proceso adicional e cero procesos non dispoñibles; e, despois, os traballadores. Configura as sondas de dispoñibilidade en /readyz e as de actividade en /healthz.
Con bases de datos de inquilino dedicadas, o paso migrate encárgase de ambas as tarefas: primeiro migra a base de datos de control e, despois, cada base enumerada en ops.tenant_database, unha por unha e co seu propio bloqueo. Un fallo nunha base de datos de inquilino non detén as demais. Cando remata con todas, compara os rexistros de migración e devolve un código de saída distinto de cero se non se aplicaron en cada base exactamente as mesmas migracións que na base de control; indica cales teñen migracións pendentes ou adiantadas. O mesmo comando instala as táboas da cola en cada base, xa que o traballador consome as tarefas dos inquilinos asociados á base onde se escribiron.
bun apps/worker/src/migrate.ts # what the Compose step runs
bun run db:migrate:all # the same, from a checkoutAccédese a cada base de datos dedicada mediante o nome co que está rexistrada. Unha base rexistrada como env:QUIRE_DB_NORTHWIND_URL require:
| Variable | Uso |
|---|---|
QUIRE_DB_NORTHWIND_URL |
Rol da aplicación, para a capa web e o traballador |
QUIRE_DB_NORTHWIND_URL_MIGRATOR |
Rol de migracións, para este comando e para os traslados |
QUIRE_DB_NORTHWIND_URL_SUPERUSER |
Opcional: volve aplicar a inicialización (roles, esquemas e utilidades) antes das migracións |
Se non se indica unha conexión _MIGRATOR para unha base rexistrada, infórmase como fallo e nunca se omite. A capa web pode actualizarse cando remate a base de control. Se unha base de inquilino vai cunha hora de atraso, amósase un aviso; cun día de atraso, envíase unha alerta.
pgvector
A partir da migración 0264, o corpus de fundamentación utiliza un índice HNSW de pgvector se o servidor ten a extensión; o servizo Compose postgres inclúe pgvector (docker/postgres.Dockerfile). A primeira execución de migrate despois de cambiar as imaxes crea a extensión mediante o proceso de inicialización do superusuario; a migración 0264 engade, a continuación, unha columna vectorial xerada e constrúe o índice. Ao engadir a columna, reescríbese app.ai_chunk unha vez baixo un bloqueo exclusivo, polo que as peticións de fundamentación agardan; non se modifica ningunha outra táboa.
Nun servidor sen pgvector, 0264 rexistra un aviso e non cambia nada; a recuperación segue sendo exacta. Se pgvector é anterior á versión 0.8, créanse a columna e o índice pero a recuperación mantense exacta ata actualizar a extensión (alter extension vector update), porque as pescudas HNSW filtradas precisan as pescudas iterativas da versión 0.8. Para activala máis adiante nun servidor sen a extensión, instálaa, volve executar a inicialización (ou create extension vector como superusuario) e, a continuación, como quire_migrator:
set maintenance_work_mem = '1GB'; -- the HNSW build is much faster in memory
select ops.ai_chunk_enable_vector_index();A operación é idempotente e devolve enabled ou unavailable. Execútaa tamén en cada base de datos de inquilino dedicada.
Reverter a actualización
Sempre se pode reverter o código: establece QUIRE_RELEASE coa etiqueta anterior e volve executar up -d. Funciona porque os esquemas son compatibles nas dúas direccións dentro dunha versión.
Non se ofrece a reversión do esquema. Isto é o que non se pode desfacer e como recuperalo:
| Irreversible | Recuperación |
|---|---|
| Unha migración de eliminación que borrou unha columna | Restaura unha copia a un punto no tempo anterior á eliminación nunha base de datos nova; extrae e combina os datos |
| Un cambio de datos in situ | O mesmo e, despois, reconcilia as escrituras realizadas desde entón |
| Webhooks e eventos enviados | Eventos compensatorios, nunca eliminación |
| Correos electrónicos enviados | Unha persoa redacta a mensaxe de seguimento |
| Cadea hash de auditoría | Nunca se reescribe; engádese unha entrada correctiva |
Por iso, a migración de eliminación publícase soa: así a restauración ten un límite claro.
Comprobar a actualización
docker compose -f docker/compose.yaml ps # every service healthy
curl -fsS http://localhost:8080/readyz # ready, and what is configured
docker compose -f docker/compose.yaml logs migrate # the migrations applied