Saltar al contenido

Ejecutar un experimento ​

Para ejecutar un experimento en un servidor desde un script o un pipeline y saber cómo fue, envíalo a POST /api/run. El servidor lo ejecuta hasta el final y responde con el resultado — o, si lo pides, con cada paso según ocurre. Esto es lo que usa signallab run --server.

Es la misma ejecución que la de Ejecutar experimento del editor y experiment_start: una tarea que cada página abierta ve y puede detener, los mismos eventos, el mismo informe en la carpeta de datos.

La solicitud ​

http
POST /api/run
Authorization: Bearer <token>
Content-Type: application/json

{ "template": "osc-ping-reply", "overrides": { "device": "192.0.2.20:9000" }, "seed": 42, "timeout": 30 }

El cuerpo nombra un experimento — un document o un template, no ambos — y con qué ejecutarlo:

CampoTipoPredeterminadoSignificado
documentobject—Un experimento tal como lo guarda y exporta el editor. Las versiones anteriores se migran, como al abrir un archivo
templatestring—Una plantilla incluida por nombre de archivo, con o sin .json (más abajo)
overridesobject{}Valores de parámetros solo para esta ejecución. Los valores pueden ser cadenas, números o booleanos; cada uno debe ser un parámetro del experimento
profilestringel del documentoEjecuta con este perfil; "" ejecuta con los predeterminados
seednumberel del documento, si no uno nuevo0 a 9007199254740991; la misma semilla sortea los mismos valores aleatorios
timeoutnumber300Segundos antes de que la ejecución falle con run.timeout; 1 a 300

Un campo que el servidor no conoce se rechaza (400, api.run_invalid). El documento se lee como se lee un archivo abierto, así que ocupa como máximo 4 MiB.

Las plantillas incluidas — los experimentos que el editor ofrece en Plantillas:

templateQué es
emptyInicio y Fin
http-checkUn GET de http://127.0.0.1:8080/, y luego una comprobación del estado 200
status-branchUn GET de http://127.0.0.1:8080/; con 200 un mensaje OSC, si no un retardo de 500 ms
parallel-flowsUn Rama paralela hacia un GET de http://127.0.0.1:8080/ y una entrada de registro, en paralelo, y luego Unir ramas
osc-ping-replyUn /ping OSC al parámetro device (127.0.0.1:9000), y luego una espera de 2 s de /pong en 127.0.0.1:9001
poll-until-readyUn Bucle que pregunta a device por /status por OSC hasta que responde ready, como máximo 10 veces
flaky-apiUna API emulada (parámetro api) que falla antes de funcionar, preguntada en un Bucle hasta que responde 200
fault-phasesUn dispositivo UDP tras un relé de degradación, al que se envía durante 8 s mientras el relé pasa por limpio, con pérdidas, offline y limpio otra vez
dependency-outageUna API emulada (parámetro api) dejada caída 2 s mientras un Bucle le pregunta hasta que responde 200 otra vez
websocket-echoUna conexión al parámetro service (ws://127.0.0.1:9001/echo), un mensaje, una espera de su eco, una comprobación, un cierre

Abre una en Plantillas para ver sus nodos y parámetros; consulta experimentos.

El resultado ​

Por defecto, la respuesta es 200 con Content-Type: application/json, enviada cuando la ejecución ha terminado: un objeto JSON, el resultado de la ejecución.

json
{
  "job_id": 12,
  "experiment": "OSC ping → reply",
  "outcome": "passed",
  "seed": 42,
  "profile": null,
  "overridden": true,
  "params": { "device": "192.0.2.20:9000" },
  "started_ms": 1759600000000,
  "ended_ms": 1759600000310,
  "steps": [ { "job_id": 12, "ts": 1759600000001, "node_id": "start", "state": "running", "detail": "", "message_key": null, "message_params": null }, … ],
  "report_path": "/data/runs/run-1759600000000-12.json"
}
CampoTipoSignificado
job_idnumberLa tarea de la ejecución
experimentstringEl nombre del experimento
outcomestringpassed, failed o stopped
seednumberLa semilla con la que se ejecutó: devuélvela como seed para sortear los mismos valores
profilestring or nullEl perfil con el que se ejecutó
overriddenbooleanAlgunos valores vinieron de overrides
paramsobjectCada valor de parámetro que usó la ejecución
started_ms, ended_msnumberMilisegundos desde 1970
errorEngineErrorPor qué falló: su primer fallo. Se omite cuando se superó
stepsobject[]Cada paso en el orden en que ocurrió, como experiment://step
emulatorsobject[]Lo que recibió y respondió cada nodo Emulador: node, name, protocol, local, counts. Se omite cuando no hay ninguno
impairmentsobject[]Lo que hizo el relé de cada nodo Degradación, fase por fase. Se omite cuando no hay ninguno
report_pathstringEl informe de la ejecución en el servidor; descárgalo con /api/files. Se omite cuando no se escribió ninguno
report_errorEngineErrorPor qué no se pudo escribir el informe. Se omite en caso contrario

Los valores secretos se enmascaran en todo ello. El archivo del informe contiene los mismos pasos; consulta ejecuciones e informes.

Mientras la ejecución sigue, el servidor envía un espacio cada 15 s. JSON ignora el espacio en blanco antes de un valor, así que el resultado se sigue analizando, y un proxy no toma una ejecución larga y silenciosa por una conexión muerta.

Seguir los pasos ​

Para ver los pasos según ocurren, pide NDJSON:

http
Accept: application/x-ndjson

La respuesta es 200 con Content-Type: application/x-ndjson: un objeto JSON por línea, cada uno con un type.

typeCuándoEl resto de la línea
startedPrimero, una vezjob_id, experiment, seed, profile, overridden, started_ms
stepCada pasoEl paso, como experiment://step
heartbeatCada 15 sNada
endedÚltimo, una vezEl resultado, como arriba
text
{"job_id":12,"experiment":"OSC ping → reply","seed":42,"profile":null,"overridden":true,"started_ms":1759600000000,"type":"started"}
{"job_id":12,"ts":1759600000001,"node_id":"start","state":"running","detail":"","message_key":null,"message_params":null,"type":"step"}
…
{"job_id":12,"experiment":"OSC ping → reply","outcome":"passed",…,"type":"ended"}

Lee las líneas hasta ended; ignora un type que no conozcas. El servidor envía X-Accel-Buffering: no, así que un proxy nginx pasa cada línea de inmediato.

Estado y desenlace ​

Un estado de error HTTP significa que no se inició ninguna ejecución; el cuerpo es un EngineError:

EstadoCódigoPor qué
400api.run_invalidEl cuerpo no es una solicitud de ejecución: no es JSON, un campo desconocido, un override que no es cadena, número o booleano
400api.run_sourceNi document ni template, o ambos
415command.json_requiredNo es Content-Type: application/json
422api.template_unknownNo hay ninguna plantilla incluida con ese nombre
422file.json_invalid, file.too_large, doc.*El documento no se puede leer
422cualquier código de validación, run.override_unknown, profile.active_missing, run.limit_range, seed.range, secret.missing, transport.address_in_use…El experimento no puede iniciarse: no valida, un valor está fuera de rango, un secreto no está guardado, un puerto en el que escucha está ocupado

Una vez que la ejecución ha empezado, el estado es 200, pase lo que pase: lee outcome en el resultado.

outcomeSignificado
passedCada paso se superó y se alcanzó Fin
failedUn paso falló, o la ejecución tardó más que su timeout (run.timeout); error dice cuál y por qué
stoppedSe detuvo antes de terminar: por job_stop, Detener todo, o el apagado del servidor. steps tiene los pasos a los que llegó; no se guarda ningún informe

Un cliente que se va ​

Cerrar la conexión no detiene la ejecución. Es una tarea del servidor: se ejecuta hasta el final y guarda su informe, como hace una ejecución iniciada en un navegador cuando se cierra la pestaña. Encuéntrala con jobs_list, deténla con job_stop, y lee su informe después con experiment_runs. Cuando el servidor se apaga, la ejecución se detiene y un cliente aún conectado recibe "outcome": "stopped".

Ejemplos ​

Ejecuta una plantilla incluida y espera el desenlace:

bash
SERVER=http://127.0.0.1:1430
TOKEN=$(cat token.txt)
curl -sS -X POST "$SERVER/api/run" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"template":"osc-ping-reply","overrides":{"device":"192.0.2.20:9000"},"timeout":30}' \
  | jq -r .outcome

Envía tu propio experimento con un parámetro cambiado, e imprime cada paso según ocurre:

bash
jq '{document: ., overrides: {api: "http://192.0.2.10:8080"}, profile: ""}' smoke.json |
  curl -sSN -X POST "$SERVER/api/run" \
    -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
    -H "Accept: application/x-ndjson" --data @- |
  jq -r 'select(.type == "step") | "\(.node_id)  \(.state)  \(.detail)"'

-N evita que curl retenga las líneas. Para hacer fallar un pipeline ante una ejecución fallida, comprueba outcome:

bash
outcome=$(curl -sS -X POST "$SERVER/api/run" -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" -d '{"template":"http-check"}' | jq -r .outcome)
[ "$outcome" = "passed" ]

Desde la línea de comandos ​

signallab run con --server <url> se ejecuta en un servidor a través de este endpoint: envía el experimento que leyó, con overrides, seed y timeout, pide NDJSON e imprime cada paso según llega su línea. El token viene de --token-file, si no de SIGNALLAB_TOKEN. Con --report descarga el informe a través de /api/files. Un servidor que no envía nada durante 60 s — ni siquiera un latido — cuenta como desaparecido.