Saltar al contenido

Actualizar sin tiempo de inactividad

Actualiza Quire autoalojado sin tiempo de inactividad.

Ver como Markdown

Las reglas están en la sección 7 de docs/architecture/23-ops.md y en la sección 4.1 de docs/architecture/07-data.md. Este es el procedimiento.

La garantía que lo hace seguro

La versión R funciona correctamente con el esquema R y con el esquema R menos uno. Cada cambio de esquema se divide en ampliación, transición y contracción:

  1. Ampliación: agrega la nueva columna, tabla o índice. El código anterior la ignora.
  2. Transición, durante al menos una versión: el código nuevo escribe en ambos formatos y lee el nuevo; una tarea reanudable completa las filas anteriores.
  3. Contracción: elimina el formato anterior en una versión posterior y por separado.

Así, durante una actualización gradual, los procesos anteriores y nuevos pueden compartir una base de datos. No hay migraciones inversas: una migración que eliminó una columna hace una hora no puede recuperar las filas que se escribieron durante esa hora.

El trabajo de CI schema-compat verifica esta garantía en cada versión: ejecuta las pruebas de la versión anterior contra el esquema nuevo.

Antes de empezar

  1. Lee las notas de la versión. Si una versión necesita una ventana de mantenimiento, se indica el tiempo estimado; hay como máximo una por versión.
  2. Ejecuta el simulacro de restauración o confirma que terminó correctamente con esta versión (backup-restore.md). Si falla, no se puede continuar con la actualización.
  3. Crea un respaldo base: docker compose -f docker/compose.yaml --profile backup run --rm backup.

Docker Compose, un solo 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 scheduler

El orden es intencional:

  1. Primero, migra, mientras la versión anterior sigue atendiendo tráfico. Las migraciones de ampliación son invisibles para ella.
  2. Luego, la capa web. Al recibir SIGTERM, cada proceso web cambia /readyz a draining, termina las solicitudes en curso en un máximo de 30 segundos, cierra los flujos con una indicación para volver a conectarse y sale. stop_grace_period es de 40 segundos para que Compose no interrumpa un apagado correcto.
  3. Al final, los workers, para que se genere el formato de evento más nuevo antes de que lo espere el consumidor nuevo. Los workers dejan de obtener tareas de inmediato y tienen 120 segundos para terminarlas; si una tarea no acaba, otro proceso la vuelve a obtener. Es seguro porque todas las tareas son idempotentes. El scheduler transfiere el liderazgo en el siguiente turno.

En un solo host, Compose reemplaza cada contenedor por turnos, así que hay una interrupción breve por servicio. Para evitar cualquier interrupción, ejecuta la capa web en dos contenedores detrás de tu propio proxy (con un archivo de reemplazo que agregue un segundo servicio web sin puerto publicado) y vuelve a crearlos de uno en uno; espera a que cada uno esté saludable antes de pasar al siguiente.

Varios hosts u orquestador

Sigue el mismo orden: ejecuta una tarea de migración y luego actualiza la capa web de forma gradual, con una instancia adicional disponible y ninguna fuera de servicio; después actualiza los workers. Configura las comprobaciones de preparación en /readyz y de disponibilidad en /healthz.

Con bases de datos de tenants dedicadas, el paso migrate hace ambas cosas: primero migra la base de datos de control y luego cada base de datos enumerada en ops.tenant_database, una por una y con su propio bloqueo. Si falla una base de tenant, las demás se procesan igual. Cuando termina con todas, compara los historiales de migración y devuelve un código distinto de cero, a menos que cada base haya aplicado exactamente las migraciones de la base de control; indica cuáles están atrasadas o adelantadas. El mismo comando instala las tablas de la cola en cada base porque el worker consume ahí las tareas del tenant fijado.

bun apps/worker/src/migrate.ts   # what the Compose step runs
bun run db:migrate:all                            # the same, from a checkout

Se accede a cada base dedicada mediante el nombre con el que está registrada. Una base registrada como env:QUIRE_DB_NORTHWIND_URL necesita:

Variable Se usa para
QUIRE_DB_NORTHWIND_URL Rol de aplicación, para la capa web y el worker
QUIRE_DB_NORTHWIND_URL_MIGRATOR Rol de migración, para este comando y los traslados
QUIRE_DB_NORTHWIND_URL_SUPERUSER Opcional: vuelve a ejecutar la inicialización (roles, esquemas y funciones auxiliares) antes de migrar

Si una base registrada no tiene una conexión _MIGRATOR, se informa como error; nunca se omite. La capa web puede actualizarse cuando termine la base de control. Si una base de tenant lleva una hora atrasada, se genera una advertencia; si lleva un día, se envía una alerta de prioridad alta.

pgvector

Desde la migración 0264, el corpus de fundamentación usa un índice pgvector HNSW cuando el servidor tiene la extensión; el servicio postgres de Compose se compila con ella (docker/postgres.Dockerfile). El primer migrate después de cambiar las imágenes crea la extensión mediante la inicialización de superusuario y luego la migración 0264 agrega una columna vectorial generada y crea el índice. Al agregar la columna, se reescribe app.ai_chunk una vez con un bloqueo exclusivo, así que las solicitudes de fundamentación esperan; ninguna otra operación toca esa tabla.

En un servidor sin pgvector, 0264 muestra un aviso y no cambia nada; la recuperación sigue siendo exacta. Con una versión de pgvector anterior a 0.8, se crean la columna y el índice, pero la recuperación sigue siendo exacta hasta actualizar la extensión (alter extension vector update), porque los recorridos HNSW filtrados requieren los recorridos iterativos de la versión 0.8. Para activarla más adelante en un servidor que no la tenga, instala la extensión, vuelve a ejecutar la inicialización (o create extension vector como superusuario) y después ejecuta, como quire_migrator:

set maintenance_work_mem = '1GB';  -- the HNSW build is much faster in memory
select ops.ai_chunk_enable_vector_index();

Es idempotente y devuelve enabled o unavailable. Ejecútala también en cada base de datos de tenant dedicada.

Revertir

Siempre se puede revertir el código: configura QUIRE_RELEASE con la etiqueta anterior y vuelve a ejecutar up -d. Funciona porque el esquema es compatible en ambos sentidos dentro de una versión.

No se permite revertir el esquema. Estas son las acciones irreversibles y cómo recuperarse:

Acción irreversible Recuperación
Una migración de contracción que eliminó una columna Restaurar a un momento anterior a la eliminación en una base nueva; después, extraer y combinar los datos
Un cambio de datos en el lugar Lo mismo y luego conciliar las escrituras posteriores
Webhooks y eventos enviados Eventos compensatorios, nunca se eliminan
Correos enviados Una persona redacta el mensaje de seguimiento
Cadena hash de auditoría Nunca se reescribe; se agrega una entrada de corrección

Por eso las migraciones de contracción se despliegan solas: así la restauración tiene un límite claro.

Verificar la 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
Navegación

Escribe para buscar…

↑↓ navegar↵ seleccionarEsc cerrar