Zaroz
Unidades que controla tu código

Señales

Una unidad habla con la plataforma a través de un pequeño agente que corre a su lado y comparte el directorio /zaroz. No hay ningún puerto de red: escribes archivos o llamas a un socket Unix.

Lo que una unidad puede señalar (contrato v1, un conjunto cerrado)

SeñalSignificado
readyHe cargado; envíame tráfico. Solo se necesita con readiness: signal
accepting true o falsedentro o fuera del conjunto balanceado sin dejar de estar sana. false saca la unidad del tráfico y de la asignación en aproximadamente un segundo
idle, busylo que está haciendo la unidad. Guía idle_action y las decisiones de despliegue y de reducción. Solo se registran las transiciones
shutdownHe terminado. Igual que salir con código 0

Los nombres desconocidos los ignora y registra el agente, nunca son fatales.

Con archivos

TerminalCode
echo > /zaroz/signals/ready echo false > /zaroz/signals/accepting # llena: deja de enviar jugadores echo true > /zaroz/signals/accepting echo > /zaroz/signals/idle echo > /zaroz/signals/busy echo > /zaroz/signals/shutdown

El agente consume cada archivo cuando aparece. Un archivo accepting vacío significa true.

Con el socket

HTTP/1.1 sobre el socket Unix /zaroz/signal.sock:

TerminalCode
curl --unix-socket /zaroz/signal.sock -X POST http://unit/ready curl --unix-socket /zaroz/signal.sock -X POST http://unit/accepting -d false curl --unix-socket /zaroz/signal.sock http://unit/unit curl --unix-socket /zaroz/signal.sock http://unit/user-data curl --unix-socket /zaroz/signal.sock "http://unit/allocation?wait=60" # long-poll de hasta 60 s curl --unix-socket /zaroz/signal.sock "http://unit/state?wait=60" # responde cuando empieza el drenaje

Lo que recibe una unidad

ArchivoContenido
/zaroz/unit.jsonclave, etiquetas (se actualizan en vivo), origen, workload, nombre privado, endpoints públicos
/zaroz/user-data.jsontu user_data, o null
/zaroz/allocation.jsonnull hasta que se asigna; después {id, allocated_at, generation}
/zaroz/state.json{draining: false} o {draining: true, reason: "stop" | "destroy" | "replace" | "scale_down"}

Cada archivo se escribe de forma atómica (un nombre temporal y después un renombrado), así que un lector nunca ve medio archivo. Vuelve a leerlos cuando cambien allocation.json o state.json; los long-polls ?wait= del socket evitan sondear.

Una unidad mínima

TypeScriptCode
import { watch, readFileSync, writeFileSync } from "node:fs"; const dir = process.env.ZAROZ_DIR ?? "/zaroz"; const read = (f: string) => JSON.parse(readFileSync(`${dir}/${f}`, "utf8")); const signal = (name: string, body = "") => writeFileSync(`${dir}/signals/${name}`, body); await startMyServer(); // carga el mapa, abre el puerto signal("ready"); watch(`${dir}/allocation.json`, () => { const allocation = read("allocation.json"); if (allocation) startMatch(read("user-data.json")); // aquí llega la lista de jugadores }); watch(`${dir}/state.json`, () => { if (read("state.json").draining) { signal("accepting", "false"); // deja de aceptar jugadores nuevos finishMatchThenExit(); // sal con 0 al terminar } });

A dónde van las señales

El agente las escribe en un objeto por unidad dentro del clúster, que la plataforma vigila. Nada de lo que se factura depende de una señal, así que un programa que mienta con sus señales solo puede detener, destruir por inactividad o marcar como llena su propia unidad.

Si la región no es alcanzable, las unidades siguen sirviendo y balanceando (la disponibilidad es local); la asignación responde 503 region-unreachable.

Last modified on