Referencia de nodos
Cada tipo de nodo que puede contener un experimento, en los grupos del menú de añadir: acciones, esperas, emulación, fallos, datos, comprobaciones y flujo. Cómo añadirlos y conectarlos está en El editor; signallab nodes imprime el mismo catálogo como JSON, para scripts y asistentes (La línea de comandos).
Cómo leer esta página
Cada nodo tiene una tabla de sus campos:
- Campo es el nombre en el panel de propiedades; En el archivo es la clave en el JSON del experimento.
- Predeterminado es lo que recibe un nodo cuando lo añades en el editor. Donde un archivo puede omitir una clave, el valor que toma entonces se indica como si falta; las demás claves son obligatorias en un archivo.
- Plantillas: sí — el campo admite
{{templates}}: parámetros, variables definidas antes, secretos y generadores, resueltos al ejecutarse el paso (Datos y plantillas). Solo parámetros — se abre antes del primer paso, cuando solo se conocen los parámetros. No — el valor se toma tal como se escribe.
Los tiempos están en milisegundos. Los límites se comprueban antes de que empiece una ejecución; un campo fuera de rango impide que el experimento se ejecute y se muestra en el nodo.
Un nodo en un archivo
En un archivo de experimento, un nodo es un objeto con un id (único en el experimento), su type, su lugar en el lienzo (x, y, cero o más), sus campos y los ajustes que usa (retry, repeat, load, omitidos cuando están desactivados). Un cable es una arista desde la salida de un nodo (port, next si falta) hasta otro nodo:
{
"nodes": [
{ "id": "start", "type": "start", "x": 40, "y": 80 },
{ "id": "ping", "type": "udp", "x": 270, "y": 80, "target": "127.0.0.1:9000", "text": "PING",
"retry": { "attempts": 3, "delay_ms": 500, "backoff": "fixed" } },
{ "id": "end", "type": "end", "x": 500, "y": 80 }
],
"edges": [
{ "from": "start", "to": "ping", "port": "next" },
{ "from": "ping", "to": "end", "port": "next" }
]
}Los ejemplos de abajo muestran un nodo cada uno, tal como lo contiene un archivo.
Ajustes compartidos por muchos nodos
Se activan en la parte inferior de las propiedades de un nodo. Qué nodo admite cuál se indica bajo cada nodo.
| Ajuste | Lo admite | Qué hace |
|---|---|---|
| Reintentar | Nodos que envían o escuchan: Solicitud HTTP, Mensaje TCP, Mensaje OSC, Datagrama UDP, Publicación MQTT, Conectar WebSocket, Enviar por WebSocket, y todas las esperas | Vuelve a intentarlo cuando falla el paso |
| Repetir | Nodos que envían: Solicitud HTTP, Mensaje TCP, Mensaje OSC, Datagrama UDP, Publicación MQTT, Enviar por WebSocket | Envía una y otra vez, un número de veces o durante un tiempo |
| Carga | Solicitud HTTP | Envía la solicitud según un perfil de carga, medido y juzgado por umbrales |
| Esperar una respuesta | Mensaje OSC, Datagrama UDP | Envía y espera la respuesta en el mismo paso |
Reintentar
reintentar si falla: cuando falla el paso — sin conexión, un tiempo de espera agotado, una espera sin nada que coincida — hace una pausa y se ejecuta de nuevo. Cada intento fallido es una fila en la línea de tiempo; el paso falla cuando falla el último intento. Una plantilla que no se puede resolver no se reintenta. Detener también termina una pausa.
| Campo | En el archivo | Qué | Predeterminado y límites |
|---|---|---|---|
| Intentos | retry.attempts | Intentos en total, el primero incluido | 3; 2–10 en el editor (un archivo también puede decir 1) |
| Pausa, ms | retry.delay_ms | La pausa antes del segundo intento | 500; 0–60 000 |
| Pausas | retry.backoff | iguales (fixed): la misma pausa cada vez; que se duplican (exponential): el doble de larga tras cada fallo | fixed (también si falta) |
Ninguna pausa dura más de 60 segundos, por mucho que se duplique. Una espera cuya salida Tiempo agotado tiene un cable no falla por un tiempo de espera agotado — sale por esa salida — así que entonces no se reintenta.
Repetir
repetir el envío: el nodo envía una y otra vez — un latido, un sondeo, un flujo constante — sin un bucle en el grafo. Cada envío lee sus plantillas de nuevo ({{counter}} es su número, {{now}} su hora), y Reintentar, cuando está activado, se aplica a cada envío. El paso se supera cuando lo hizo cada envío; un envío que falla definitivamente falla el paso. La línea de tiempo informa del progreso como máximo una vez por segundo.
| Campo | En el archivo | Qué | Predeterminado y límites |
|---|---|---|---|
| Repetir | repeat.until | un número de veces (count) o durante un tiempo (duration) | count (también si falta) |
| Veces | repeat.count | Envíos en total, el primero incluido | 10 (también si falta); 2–10 000 |
| Durante, ms | repeat.duration_ms | Cuánto tiempo seguir enviando, desde el primer envío | 10 000 (también si falta); 1–300 000 |
| Cada, ms | repeat.interval_ms | La pausa entre dos envíos | 1 000; 10–60 000; obligatorio en un archivo |
| Jitter, ms | repeat.jitter_ms | Cada pausa hasta este tiempo más larga, extraída de la semilla de la ejecución | 0 (también si falta); 0–60 000 |
Las repeticiones deben caber en los 300 segundos de una ejecución, y durante un tiempo debe necesitar menos de 10 000 envíos (su tiempo dividido entre el intervalo).
Carga
enviar bajo carga, solo en un Solicitud HTTP: la solicitud se envía según un perfil — una tasa constante, una rampa, escalones, un pico o llegadas aleatorias — con hasta 512 en vuelo a la vez (32 por defecto), y se mide: latencias, errores, la tasa alcanzada. Los umbrales deciden si el paso se supera. La carga sustituye a Repetir y Reintentar (una solicitud fallida se cuenta, no se reintenta) y no deja respuesta para las comprobaciones posteriores. Sus campos y resultados están en Pruebas de carga.
Esperar una respuesta
esperar una respuesta, en un Mensaje OSC o un Datagrama UDP: el mensaje se envía desde el puerto en el que se espera la respuesta, así que se oye a un dispositivo que responde al remitente, y el paso solo se supera cuando llega una respuesta que coincide a tiempo. Sin respuesta, el paso falla — Reintentar envía de nuevo. La respuesta se guarda en una variable, como la de una espera.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Respuesta en (IP:puerto) | reply.bind | IP:port desde el que enviar y en el que escuchar; el puerto 0 toma cualquier puerto libre | 0.0.0.0:0 | No |
| Patrón de dirección de respuesta (OSC) | reply.address | El patrón de dirección de la respuesta, como en Esperar OSC | /* | Sí |
| Reglas de argumentos (OSC) | reply.args | Reglas de argumentos, como en Esperar OSC | ninguna; como máximo 16 | Valores: sí |
| Carga útil de respuesta (UDP) | reply.mode | any, contains, regex o hex — consulta Coincidencia de cargas útiles | any (también si falta) | No |
| Patrón (UDP) | reply.pattern | Lo que la respuesta debe contener o con lo que debe coincidir | vacío; obligatorio salvo any | Sí |
| Tiempo de espera, ms | reply.timeout_ms | Cuánto esperar | 2 000 (también si falta); 1–120 000 | No |
| Variable de respuesta | reply.variable | La variable en la que se guarda la respuesta | reply (también si falta) | No |
El puerto de la respuesta se abre antes del primer paso, como el de una espera.
Acciones
Nodos que envían. Una espera tras una acción cuenta los mensajes desde el momento en que empezó la acción.
Solicitud HTTP
Envía una solicitud HTTP y guarda la respuesta para las comprobaciones, las ramas y los nodos Extraer valor posteriores.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Método | request.method | GET, HEAD, POST, PUT, PATCH, DELETE u OPTIONS (un archivo puede nombrar cualquier método) | GET | No |
| URL | request.url | Una URL http:// o https:// | http://127.0.0.1:8080/ | Sí |
| Tiempo de espera (ms) | request.timeout_ms | Para todo el intercambio | 4 000 (10 000 si falta); 1–120 000 | No |
| Encabezados de la solicitud | request.headers | [[name, value], …]; se omite una fila con un nombre vacío | ninguna | Sí, nombres y valores |
| Cuerpo | request.body | Texto, o null para ninguno | null | Sí |
| Autenticación | request.auth | Ninguna, Basic, Token Bearer o Digest, con Nombre de usuario y Contraseña, o Token | ninguno | Sí |
- Cualquier respuesta supera el paso, 404 y 500 incluidos: comprueba el estado con Estado HTTP o ramifícalo con Rama por estado. Una solicitud que no obtiene respuesta — rechazada, un tiempo de espera agotado, un nombre que no se resuelve, un certificado que no es de confianza — falla el paso.
- Se siguen las redirecciones, como máximo diez. Los certificados
https://se verifican. - El cuerpo de la respuesta se conserva hasta 256 KiB para las comprobaciones; un cuerpo mayor se corta ahí (las comprobaciones lo indican cuando lo que buscan puede estar más allá del corte).
- Digest responde al desafío 401 del servidor y envía la solicitud de nuevo. Las credenciales solo entran en la solicitud: los pasos, los informes y el Inspector nunca muestran el encabezado
Authorization. Escribe una contraseña como{{secret.NAME}}. - Mientras el experimento conserva las cookies (activado por defecto, en Parámetros), lo que los servidores establecen se devuelve con las solicitudes posteriores de la ejecución a ellos.
Salidas: Salida. Ajustes: Reintentar, Repetir, Carga.
{ "id": "cue", "type": "http", "x": 270, "y": 80,
"request": { "method": "POST", "url": "{{api}}/cue", "headers": [["Content-Type", "application/json"]],
"body": "{\"cue\": 1}", "timeout_ms": 5000,
"auth": { "scheme": "bearer", "token": "{{secret.API_TOKEN}}" } } }Véase también HTTP.
Mensaje TCP
Se conecta a un host por TCP, escribe la carga útil, espera hasta 250 ms los primeros bytes de una respuesta (lee como máximo 1 024 bytes, una vez) y cierra la conexión. El tamaño de la respuesta se informa, no se comprueba.
En el Inspector el paso son dos tramas tcp con el origen experiment: la carga útil escrita y, cuando llegó una, la respuesta leída. Los secretos en uso se enmascaran en ambas, como en cualquier trama.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Host | host | Un nombre de host o una dirección IP | 127.0.0.1 | Sí |
| Puerto | port | 9000; 1–65 535 | No | |
| Tiempo de espera (ms) | timeout_ms | Para conectarse, escribir y la respuesta en conjunto | 4 000 (también si falta); 1–120 000 | No |
| Carga útil | payload | El texto escrito una vez conectado, como UTF-8 | hello | Sí |
El paso falla cuando se rechaza la conexión, no se resuelve el nombre o se agota el tiempo. Salidas: Salida. Ajustes: Reintentar, Repetir. Enviar ahora se conecta y escribe la carga útil una vez, y el resultado del nodo indica cuántos bytes se enviaron y volvieron.
{ "id": "go", "type": "tcp", "x": 270, "y": 80, "host": "127.0.0.1", "port": 5000, "payload": "GO\r\n", "timeout_ms": 2000 }Mensaje OSC
Envía un mensaje OSC 1.0 por UDP.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Host:puerto de destino | target | IP:port o host:port; un nombre de host se resuelve cuando el paso envía, y se toma su dirección IPv4 cuando la tiene | 127.0.0.1:9000 | Sí |
| Dirección OSC | address | Empieza por / | /test | Sí |
| Argumentos | args | [{ "type", "value" }, …] — int, float, str, long, double, bool, blob (bytes), nil (sin valor) | ninguna | Valores de texto (str): sí |
| esperar una respuesta | reply | Opcional: enviar y esperar la respuesta — consulta Esperar una respuesta | Desactivado |
Salidas: Salida; cuando se espera una respuesta, solo se sigue cuando llegó la respuesta. Ajustes: Reintentar, Repetir, una respuesta. ⚡ Pasar por una degradación en sus propiedades pone un Degradación delante.
{ "id": "fader", "type": "osc", "x": 270, "y": 80, "target": "{{device}}", "address": "/fader/1",
"args": [{ "type": "float", "value": 0.75 }] }Véase también OSC.
Datagrama UDP
Envía una carga útil de texto como un datagrama UDP a uno o varios destinos.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Host:puerto de destino | target | IP:port o host:port; varios separados por comas, puntos y comas o saltos de línea reciben cada uno el datagrama. Un nombre de host se resuelve cuando el paso envía, y se toma su dirección IPv4 cuando la tiene | 127.0.0.1:9000 | Sí |
| Carga útil | text | La carga útil, como UTF-8 | hello; como máximo 65 507 bytes | Sí |
| esperar una respuesta | reply | Opcional: enviar y esperar la respuesta — consulta Esperar una respuesta | Desactivado |
El paso falla si no se puede alcanzar algún destino. Salidas: Salida. Ajustes: Reintentar, Repetir, una respuesta.
{ "id": "ping", "type": "udp", "x": 270, "y": 80, "target": "{{device}}", "text": "PING {{run.id}}",
"reply": { "bind": "0.0.0.0:0", "mode": "contains", "pattern": "PONG", "timeout_ms": 1000, "variable": "pong" } }Publicación MQTT
Se conecta a un bróker MQTT, publica un mensaje y se desconecta. La conexión es MQTT 3.1.1 sobre TCP sin cifrar, con una sesión limpia y sin nombre de usuario ni contraseña. La conexión, la publicación y el acuse del bróker deben ocurrir en 15 segundos.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Host del bróker | host | El nombre o la dirección del bróker | 127.0.0.1 | Sí |
| Puerto | port | 1883; 1–65 535 | No | |
| Tema | topic | Sin comodines (+, #) | lab/test | Sí |
| Carga útil | payload | El mensaje, como texto | hello | Sí |
| QoS | qos | 0, 1 o 2 | 0 | No |
| Retener mensaje | retain | true: el bróker lo conserva como el valor del tema | false | No |
Las seis claves son obligatorias en un archivo. El paso falla cuando no se puede alcanzar el bróker o rechaza la conexión o el mensaje. Salidas: Salida. Ajustes: Reintentar, Repetir.
{ "id": "light", "type": "mqtt", "x": 270, "y": 80, "host": "{{broker}}", "port": 1883,
"topic": "lab/light/1/set", "payload": "on", "qos": 1, "retain": false }Véase también MQTT.
Conexión WebSocket
Abre un WebSocket para el resto de la ejecución, o hasta un Cerrar WebSocket. Lo que llega a partir de entonces se guarda para los pasos Esperar WebSocket sobre él. La URL y los encabezados se resuelven cuando se ejecuta el paso, así que un token extraído antes puede estar en ellos. Si se ejecuta de nuevo — en un Bucle — cierra primero su conexión anterior y abre una nueva. Cuando termina la ejecución, de cualquier forma, sus conexiones se cierran con una trama de cierre.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| URL | url | Una URL ws:// o wss:// | ws://127.0.0.1:9001/ | Sí |
| Encabezados de la solicitud | headers | [[name, value], …] enviados con la solicitud de mejora | ninguno | Sí, nombres y valores |
| Subprotocolos | protocols | Subprotocolos que ofrecer, por orden de preferencia; el servidor elige uno | ninguno | No |
| Tiempo de espera (ms) | timeout_ms | Para conectarse y la mejora | 5 000 (10 000 si falta); 1–120 000 | No |
wss:// confía en los mismos certificados que https://. El paso falla cuando falla la conexión o la mejora; el estado del servidor está en el motivo. Salidas: Salida. Ajustes: Reintentar (no Repetir).
{ "id": "socket", "type": "ws_connect", "x": 270, "y": 80, "url": "ws://127.0.0.1:9001/chat",
"headers": [["Authorization", "Bearer {{token}}"]], "protocols": ["chat.v1"], "timeout_ms": 5000 }Véase también WebSocket.
Envío WebSocket
Envía un mensaje por la conexión que abrió un Conectar WebSocket.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Conexión | connection | El id de un nodo Conectar WebSocket de este experimento | el primero | No |
| Formato | binary | Texto (false), o Binario (hex) (true): la carga útil son bytes escritos en hex, de ad be ef | false (también si falta) | No |
| Carga útil | text | El mensaje | hello; como máximo 16 MiB | Sí |
La conexión debe preceder al envío en su ruta; un envío cuya conexión no está abierta falla. Las respuestas cuentan desde el momento en que se escribe el mensaje. Salidas: Salida. Ajustes: Reintentar, Repetir.
{ "id": "hello", "type": "ws_send", "x": 500, "y": 80, "connection": "socket",
"text": "{\"type\":\"ping\",\"id\":\"{{uuid}}\"}", "binary": false }Cierre WebSocket
Cierra una conexión con un saludo de cierre. La línea de tiempo dice quién la cerró: este paso, el servidor antes (con su código), o una conexión que se había roto.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Conexión | connection | El id de un nodo Conectar WebSocket | el primero | No |
| Código de cierre | code | 1000 (normal), o 3000–4999 para uno propio de la aplicación | 1000 (también si falta) | No |
| Motivo | reason | Se envía con el código | vacío; como máximo 123 bytes, tras las plantillas | Sí |
Salidas: Salida. Sin ajustes.
{ "id": "bye", "type": "ws_close", "x": 960, "y": 80, "connection": "socket", "code": 1000, "reason": "done" }Marca de registro
Escribe una línea en la línea de tiempo y el informe — un punto de control, o los valores a los que llegó una ejecución.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Mensaje | message | El texto | Check point; como máximo 10 000 caracteres | Sí |
Salidas: Salida. Sin ajustes.
{ "id": "ready", "type": "log", "x": 500, "y": 80, "message": "device {{device}} ready" }Esperas
El grupo Observar: nodos que esperan que llegue algo. Comparten estas reglas:
- Escuchan desde el principio de la ejecución. El puerto o la suscripción al bróker de una espera se abre antes del primer paso, así que no se pierde un dispositivo que responde más rápido de lo que empieza el siguiente paso. Dos esperas en la misma dirección comparten un socket.
- Cuentan desde la última acción de su rama. Un mensaje que llegó antes de la última solicitud de la rama no es una respuesta a ella; antes de cualquier acción, cuenta todo desde que empezó la ejecución.
- Se toma el primer mensaje que coincide. Un mensaje que tomó una espera no lo ve otra.
- Coincide o Tiempo agotado. Cuando coincide, el mensaje se guarda en la variable de la espera y el flujo sigue por Coincide. Cuando se agota el tiempo, sigue por Tiempo agotado si esa salida tiene un cable; si no, el paso falla, indicando cuántos otros mensajes llegaron.
- Cada socket conserva los 1 024 mensajes más recientes (y 64 MiB); los más antiguos se descartan, y un tiempo de espera agotado dice cuántos eran.
- Escuchar ahora escucha con ese único paso, a partir de ahora.
Salidas: Coincide (obligatoria), Tiempo agotado (opcional). Ajustes: Reintentar.
Coincidencia de cargas útiles
Esperar UDP, Esperar MQTT, Esperar WebSocket y una respuesta UDP eligen cómo debe ser la carga útil:
| Opción | En el archivo | Coincide cuando la carga útil |
|---|---|---|
| Cualquier datagrama | any | es cualquier cosa |
| Contiene el texto | contains | leída como texto UTF-8, contiene el patrón (distingue mayúsculas y minúsculas) |
| Coincide con la regex | regex | leída como texto UTF-8, coincide con la expresión regular |
| Contiene los bytes (hex) | hex | contiene los bytes, escritos como pares hex: de ad be ef, deadbeef, 0xde,0xad, DE:AD |
El mensaje que coincidió se guarda como un objeto. Los pasos posteriores leen sus campos como {{reply.text}} (con el nombre de la variable en lugar de reply):
| Campo | Qué |
|---|---|
text | La carga útil como texto |
hex, bytes | La carga útil en hex (sus primeros 1 024 bytes), y su tamaño en bytes |
match | Lo que coincidió: el texto, el primer grupo de la expresión regular (o toda la coincidencia), o los bytes |
from | El IP:port del remitente |
ms | Milisegundos desde la última acción de la rama (o el inicio de la ejecución) hasta el mensaje |
topic | Esperar MQTT: el tema en el que se publicó |
json, kind | Esperar WebSocket: el mensaje analizado como JSON (null cuando no lo es), y text o binary |
Esperar OSC
Espera un mensaje OSC cuya dirección coincide con un patrón y cuyos argumentos cumplen todas las reglas. En un bundle, se toma el primer mensaje que coincide.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Escuchar en (IP:puerto) | bind | IP:port en el que escuchar; 0.0.0.0 para todas las tarjetas de red | 127.0.0.1:9001 | No |
| Patrón de dirección | address | * cualquier carácter, ? uno, [0-9] un conjunto ([!0-9] fuera de él), {ping,pong} cualquiera de los dos; los comodines se quedan dentro de un segmento / | /pong; como máximo 512 caracteres | Sí |
| Reglas de argumentos | args | [{ "index", "op", "value" }, …]: el argumento index comparado con value por op (Comparaciones); deben cumplirse todas | ninguna; como máximo 16, índice 0–63 | Valores: sí |
| Tiempo de espera, ms | timeout_ms | 2 000 (también si falta); 1–120 000 | No | |
| Variable de respuesta | variable | Dónde se guarda el mensaje | reply (también si falta) | No |
Un argumento se compara como texto: los números tal como se escriben, las cadenas sin comillas, true/false, un blob en hex. Una regla sobre un argumento que el mensaje no tiene no se cumple. El mensaje guardado tiene address, args ({{reply.args[0]}}), from y ms.
{ "id": "status", "type": "wait_osc", "x": 500, "y": 80, "bind": "0.0.0.0:9001", "address": "/status",
"args": [{ "index": 0, "op": "eq", "value": "ready" }], "timeout_ms": 5000, "variable": "reply" }Esperar UDP
Espera un datagrama UDP cuya carga útil coincide.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Escuchar en (IP:puerto) | bind | IP:port en el que escuchar | 127.0.0.1:9001 | No |
| Carga útil | mode | Consulta Coincidencia de cargas útiles | contains (any si falta) | No |
| Patrón | pattern | Lo que la carga útil debe contener o con lo que debe coincidir | pong; obligatorio salvo any | Sí |
| Tiempo de espera, ms | timeout_ms | 2 000 (también si falta); 1–120 000 | No | |
| Variable de respuesta | variable | reply (también si falta) | No |
{ "id": "ready", "type": "wait_udp", "x": 500, "y": 80, "bind": "0.0.0.0:9002", "mode": "contains",
"pattern": "READY", "timeout_ms": 5000, "variable": "reply" }Esperar MQTT
Espera un mensaje publicado en un tema de un bróker, cuya carga útil coincide. La ejecución se conecta y se suscribe antes de su primer paso. Los mensajes retenidos que el bróker reproduce al suscribirse se ignoran: solo cuenta lo que se publica después de que empezó la ejecución.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Host del bróker | host | El bróker | 127.0.0.1 | Solo parámetros |
| Puerto | port | 1883; 1–65 535 | No | |
| Filtro de temas | topic | Un filtro: + es un nivel cualquiera, # todo lo que hay debajo (solo al final) | lab/# | Solo parámetros |
| Carga útil | mode | Consulta Coincidencia de cargas útiles | any (también si falta) | No |
| Patrón | pattern | vacío; obligatorio salvo any | Sí | |
| Tiempo de espera, ms | timeout_ms | 2 000 (también si falta); 1–120 000 | No | |
| Variable de respuesta | variable | reply (también si falta) | No |
{ "id": "state", "type": "wait_mqtt", "x": 500, "y": 80, "host": "{{broker}}", "port": 1883,
"topic": "lab/+/state", "mode": "contains", "pattern": "on", "timeout_ms": 5000, "variable": "reply" }Esperar una solicitud HTTP
Espera una solicitud HTTP — un webhook, una retrollamada — al Emulador de la ejecución en esa dirección o, cuando la ejecución no tiene ahí ningún emulador HTTP, a un escucha propio de la ejecución que responde a cada solicitud con 204. La solicitud debe coincidir con el método, la ruta de acceso y todas las condiciones.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Escuchar en (IP:puerto) | bind | IP:port | 127.0.0.1:18080 — donde escucha un Emulador nuevo | No |
| Método | method | Un método, o Cualquiera (ANY); GET también acepta HEAD | ANY (también si falta) | No |
| Ruta de acceso | path | /hooks/:name nombra un segmento ({{request.params.name}}); un /* final toma el resto | /* (también si falta); como máximo 512 caracteres | Sí |
| Condiciones | when | [{ "on", "name", "op", "value" }, …] sobre un header, un parámetro query, el body o una ruta json; debe cumplirse cada uno | ninguna; como máximo 16 | Sí, nombres y valores |
| Tiempo de espera, ms | timeout_ms | 5 000 (2 000 si falta); 1–120 000 | No | |
| Variable de respuesta | variable | request (también si falta) | No |
La solicitud guardada tiene method, path, query, headers, body, json, params, from y ms: {{request.json.event}}, {{request.headers.x-key}}.
{ "id": "hook", "type": "wait_http", "x": 500, "y": 80, "bind": "127.0.0.1:18081", "method": "POST",
"path": "/hooks/:name", "when": [{ "on": "json", "name": "$.event", "op": "eq", "value": "deploy" }],
"timeout_ms": 5000, "variable": "request" }Esperar WebSocket
Espera un mensaje en la conexión que abrió un Conectar WebSocket, cuya carga útil coincide. Cuentan los mensajes desde la última acción de la rama — la propia conexión, un envío o cualquier otra solicitud.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Conexión | connection | El id de un nodo Conectar WebSocket | el primero | No |
| Carga útil | mode | Consulta Coincidencia de cargas útiles | any (también si falta) | No |
| Patrón | pattern | vacío; obligatorio salvo any | Sí | |
| Tiempo de espera, ms | timeout_ms | 2 000 (también si falta); 1–120 000 | No | |
| Variable de respuesta | variable | reply (también si falta) | No |
Un mensaje JSON se puede leer campo por campo: {{reply.json.type}}. La conexión debe preceder a la espera en su ruta.
{ "id": "pong", "type": "wait_ws", "x": 730, "y": 80, "connection": "socket", "mode": "contains",
"pattern": "pong", "timeout_ms": 3000, "variable": "reply" }Emulación
Emulador
Hace el papel de una dependencia — una API HTTP, un dispositivo OSC, UDP o TCP, un bróker MQTT — durante toda la ejecución. Se abre antes del primer paso y responde hasta que termina la ejecución; en el flujo, el paso se supera de inmediato. Lo que recibió se cuenta, regla por regla, en el informe de la ejecución.
| Campo | En el archivo | Qué | Predeterminado |
|---|---|---|---|
| Editar… | emulator | El emulador: name, bind (IP:port), protocol (http, osc, udp, tcp, mqtt), sus rutas o reglas, y una outage opcional | Una API HTTP llamada API en 127.0.0.1:18080 que responde a /health |
Las propiedades muestran lo que hace en una línea. Editar… abre sus reglas, el mismo editor que la pantalla Emuladores; A la biblioteca guarda una copia en la biblioteca de emuladores, y De la biblioteca sustituye este por una copia de ella. Las reglas — rutas, respuestas, fallos, caídas — se describen allí.
- Un emulador HTTP es también lo que lee una Esperar solicitud HTTP en su dirección; un emulador OSC o UDP comparte su puerto con las esperas de la ejecución allí.
- Dos emuladores de un mismo transporte no pueden compartir un puerto en una ejecución.
- Emulador caído/activo lo baja y lo vuelve a subir.
Salidas: Salida. Sin ajustes.
{ "id": "api", "type": "emulator", "x": 270, "y": 80,
"emulator": { "name": "Orders API", "bind": "127.0.0.1:18080", "protocol": "http",
"routes": [{ "method": "GET", "path": "/orders/:id", "order": "sequence",
"responses": [{ "status": 503 }, { "status": 200, "body": "{\"id\":\"{{request.params.id}}\"}" }] }] } }Fallos
Nodos que rompen cosas a voluntad. Una rama de nodos Pausa y estos junto al tráfico se lee como una programación; Fallos programados muestra cómo.
Degradación
Un relé de degradación durante toda la ejecución: el sistema bajo prueba envía a (o se conecta a) Escuchar en en lugar del destino real; el relé reenvía a Reenviar a, y las respuestas vuelven por el mismo camino, degradadas por el perfil. Se abre antes del primer paso y se cierra cuando termina la ejecución, de cualquier forma, así que nada queda degradado; en el flujo, el paso se supera de inmediato. Cada decisión se extrae de la semilla de la ejecución: la misma semilla y el mismo tráfico corren la misma suerte.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Escuchar en | listen | IP:port al que envía el sistema bajo prueba | 127.0.0.1:9010 | Solo parámetros |
| Reenviar a | target | IP:port del destino real, o host:port — un nombre de host se resuelve cuando empieza la ejecución, y un nombre que no se encuentra detiene la ejecución en este nodo | 127.0.0.1:9000 | Solo parámetros |
| Protocolo | protocol | UDP (udp): cada datagrama corre su propia suerte; TCP (tcp): cada conexión se une a una propia hacia el destino, y ambos flujos se degradan | UDP (udp si falta) | No |
| Preajuste y los valores bajo él | profile | Lo que el relé hace al tráfico — consulta El perfil | LAN (sin degradación si falta) | No |
La dirección de escucha de un relé no puede ser otro socket de la ejecución, y los relés no pueden reenviarse entre sí en círculo. Un destino dado por nombre se sigue una vez resuelto, así que un círculo a través de un nombre detiene la ejecución al empezar. El informe cuenta cada fase de un relé por separado.
Salidas: Salida. Sin ajustes.
{ "id": "relay", "type": "impairment", "x": 270, "y": 80, "listen": "127.0.0.1:9010", "target": "{{device}}",
"profile": { "name": "lan", "latency_ms": 1, "jitter_ms": 1 } }El perfil
Un chip de preajuste — LAN, Wi-Fi saturada, 4G, Satélite, Intermitente, Sin conexión — rellena todos los valores; cambia cualquiera de ellos después. Un relé solo lee los valores de su protocolo; en un archivo puede omitirse cualquier clave (cero, desactivado).
| Campo | En el archivo | Qué | Límites | Protocolo |
|---|---|---|---|---|
| — | name | Una etiqueta para la línea de tiempo y el informe: la clave de un preajuste (lan, wifi, 4g, satellite, intermittent, offline) o la tuya | como máximo 60 caracteres | ambos |
| Sin conexión — no pasa nada | offline | No pasa nada | true / false | ambos |
| Latencia | latency_ms | Retardo añadido a cada paquete, o trozo de un flujo | 0–60 000 (el deslizador llega a 1 000) | ambos |
| Jitter | jitter_ms | Un retardo extra aleatorio de hasta este tiempo; un flujo TCP se mantiene en orden | 0–60 000 (el deslizador llega a 500) | ambos |
| Ancho de banda, kbit/s | rate_kbps | Un límite de ancho de banda, 0 para ninguno. UDP: pasado un segundo de cola, los datagramas se descartan como limitados; TCP: se frena al emisor, no se descarta nada | 0, o 8–10 000 000 | ambos |
| Pérdida de paquetes | loss | La probabilidad de que se descarte un datagrama | 0–1 (el deslizador muestra %) | UDP |
| Pérdida en ráfagas, Longitud de ráfaga, datagramas | burst_start, burst_length | La probabilidad de que empiece una ráfaga de pérdidas, y cuántos datagramas dura de media | 0–1; 1–1 000 cuando las ráfagas están activadas | UDP |
| Duplicación | duplicate | La probabilidad de que un datagrama se envíe dos veces | 0–1 | UDP |
| Corrupción | corrupt | La probabilidad de que se invierta un bit de un datagrama | 0–1 | UDP |
| Reordenación | reorder | La probabilidad de que un datagrama se retenga, para que los posteriores lo adelanten | 0–1 | UDP |
| Restablecer conexión | reset | La probabilidad de que un trozo de un flujo reinicie su conexión en su lugar — ambos extremos reciben un reinicio | 0–1 | TCP |
| Semiabierta | stall | La probabilidad de que un trozo deje su conexión a medias: no pasa nada más en ningún sentido, y no se avisa a ninguno de los dos extremos | 0–1 | TCP |
Más sobre relés, preajustes y lo que modelan en la página Degradación.
Cambiar degradación
Cambia uno de los nodos Degradación de la ejecución a otro perfil a partir de este paso, sin soltar su puerto. La fase hasta ahora se cierra y se cuenta en el informe.
| Campo | En el archivo | Qué | Predeterminado | Plantillas |
|---|---|---|---|---|
| Degradación | relay | El id de un nodo Degradación de este experimento | el primero | No |
| Preajuste y los valores bajo él | profile | Aquello con lo que degrada a partir de ahora — consulta El perfil; el relé lee los valores de su propio protocolo | Sin conexión (sin degradación si falta) | No |
El paso falla si el relé no está en marcha — porque no logró reenviar, por ejemplo. Salidas: Salida. Sin ajustes.
{ "id": "cut", "type": "impairment_change", "x": 730, "y": 200, "relay": "relay",
"profile": { "name": "offline", "offline": true } }Bajar/subir emulador
Baja uno de los emuladores de la ejecución, o lo vuelve a subir. Mientras está caído, un emulador HTTP responde como dice Durante la caída; un dispositivo TCP y un bróker MQTT cortan sus conexiones y rechazan las nuevas; los dispositivos OSC y UDP no responden nada. Al subir de nuevo, el emulador sigue su propia programación de caídas, si la tiene.
| Campo | En el archivo | Qué | Predeterminado |
|---|---|---|---|
| Emulador | emulator | El id de un nodo Emulador de este experimento | el primero |
| Estado | down | Caído (true) o Activo (false) | caído (false si falta) |
| Durante la caída | fault | Solo HTTP: 503 No disponible (unavailable), Cerrar la conexión (reset: la conexión se cierra sin respuesta) o Sin respuesta (timeout: la solicitud se retiene hasta que el cliente se rinde, 120 s como máximo) | unavailable (también si falta) |
Salidas: Salida. Sin ajustes. Nada es una plantilla.
{ "id": "down", "type": "emulator_state", "x": 500, "y": 200, "emulator": "api", "down": true, "fault": "unavailable" }Datos
Extraer un valor
Guarda una parte de la última respuesta HTTP de su ruta como una variable, para campos posteriores ({{token}}), comprobaciones y ramas. Una solicitud HTTP debe precederlo en todas las rutas. Hacer clic en un valor de una respuesta de Enviar ahora añade uno por ti.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Variable | variable | El nombre: letras, dígitos y _, sin empezar por un dígito, ni una palabra reservada, ni el nombre de un parámetro | token | No |
| Tomar de | from | Campo JSON (json), Encabezado (header), Código de estado (status), Cuerpo completo (body) o Expresión regular (regex) | json | No |
| Ruta JSON, Nombre del encabezado o Patrón (grupo 1 si existe) | expr | Una ruta JSON ($.data.token, $.items[0], $["first name"]), el nombre de un encabezado (en cualquier caso), o una expresión regular — su primer grupo, o toda la coincidencia | $.token; no se usa para el estado y el cuerpo | No |
El paso falla cuando no hay nada que tomar: el cuerpo no es JSON, falta la ruta o el encabezado, la expresión no coincide o — para un campo JSON o todo el cuerpo — el cuerpo era más largo que los 256 KiB conservados. Un estado se guarda como número; el resto, como texto, o como el valor JSON encontrado. Salidas: Salida. Sin ajustes.
{ "id": "token", "type": "extract", "x": 500, "y": 80, "variable": "token", "from": "json", "expr": "$.data.token" }Más sobre variables en Datos y plantillas.
Comprobaciones
Una comprobación se supera, o falla la ejecución. Las cuatro comprobaciones de respuesta leen la última respuesta HTTP de su ruta, así que una solicitud HTTP — no una bajo carga — debe precederlas en todas las rutas.
Estado HTTP
Se supera cuando el estado de la última respuesta es exactamente el indicado.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Estado esperado | status | 200; 100–599 | No |
Salidas: Salida. Sin ajustes.
{ "id": "ok", "type": "assert_status", "x": 500, "y": 80, "status": 200 }Texto de la respuesta
Se supera cuando el cuerpo de la última respuesta contiene el texto, exactamente (incluidas las mayúsculas y minúsculas). Solo se conservan los primeros 256 KiB de un cuerpo: un texto que no se encuentra en un cuerpo que se cortó falla con ese motivo.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Contiene el texto | contains | ok; obligatorio | Sí |
Salidas: Salida. Sin ajustes.
{ "id": "ready", "type": "assert_body", "x": 500, "y": 80, "contains": "ready" }Encabezado de la respuesta
Se supera cuando la última respuesta tiene el encabezado y su valor contiene el texto. El nombre del encabezado coincide en cualquier caso; el valor, exactamente.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Nombre del encabezado | name | content-type; obligatorio | Sí | |
| Contiene el texto | contains | Lo que debe contener su valor; vacío: el encabezado solo tiene que estar | application/json | Sí |
Salidas: Salida. Sin ajustes.
{ "id": "json", "type": "assert_header", "x": 500, "y": 80, "name": "Content-Type", "contains": "json" }Tiempo de respuesta
Se supera cuando la última respuesta tardó como máximo este tiempo, desde el envío de la solicitud hasta el final de su cuerpo.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Tiempo máximo, ms | max_ms | 1 000; 1–120 000 | No |
Salidas: Salida. Sin ajustes.
{ "id": "fast", "type": "assert_latency", "x": 500, "y": 80, "max_ms": 250 }Comprobar un valor
Compara un valor — normalmente una variable, escrita como plantilla — con uno esperado, y se supera cuando se cumple la comparación.
| Campo | En el archivo | Qué | Predeterminado | Plantillas |
|---|---|---|---|---|
| Valor | value | Lo que se compara: {{token}}, {{reply.args[0]}} | {{token}} | Sí |
| Condición | op | Consulta Comparaciones | no está vacío | No |
| Esperado | expected | No lo usan está vacío ni no está vacío | vacío (también si falta) | Sí |
Salidas: Salida. Sin ajustes.
{ "id": "state", "type": "assert_value", "x": 730, "y": 80, "value": "{{state}}", "op": "eq", "expected": "ready" }Comparaciones
Comprobar valor, Rama por valor, la condición de salida de un Bucle, las reglas de argumentos de OSC y las condiciones HTTP comparan del mismo modo:
| Opción | En el archivo | Se cumple cuando el valor |
|---|---|---|
| es igual a | eq | es igual al esperado — como números cuando ambos son números (200 = 200.0), si no como texto exacto |
| no es igual a | ne | no es igual a él, por la misma regla |
| menor que, como máximo, mayor que, como mínimo | lt, le, gt, ge | es menor, como máximo, mayor, como mínimo — ambos deben ser números: si no, una comprobación, una rama o un Bucle falla el paso, y una regla de argumentos o una condición HTTP no se cumple |
| contiene | contains | contiene el texto esperado |
| coincide con la regex | matches | coincide con la expresión regular esperada |
| está vacío, no está vacío | empty, not_empty | está vacío (los espacios cuentan como vacío) / no lo está |
Flujo
Nodos que deciden adónde va la ejecución. Más sobre ramas, uniones y bucles en Flujo.
Inicio
Donde empieza la ejecución; cada experimento tiene exactamente uno. No tiene entrada ni campos. La primera fila de la línea de tiempo da la semilla de la ejecución.
Salidas: Salida, obligatoria. Varios cables desde él inician ramas paralelas a la vez.
{ "id": "start", "type": "start", "x": 40, "y": 80 }Fin
Donde se completa la ejecución; cada experimento tiene exactamente uno, y no tiene salidas. Varias ramas pueden conducir a él: la ejecución se supera una vez, después de que termine la última rama, y solo si ninguna falló. Una ejecución que nunca llega a Fin falla.
{ "id": "end", "type": "end", "x": 960, "y": 80 }Retardo
Espera un tiempo fijo antes del siguiente paso.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Pausa (ms) | ms | 300; 0–60 000 | No |
Salidas: Salida. Sin ajustes. Para esperas más largas, pon varios en fila o en un Bucle.
{ "id": "pause", "type": "delay", "x": 500, "y": 80, "ms": 500 }Rama por estado
Elige Sí cuando la última respuesta HTTP tiene este estado, si no No. Una solicitud HTTP debe precederla en todas las rutas.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Estado esperado | status | 200; 100–599 | No |
Salidas: Sí y No, ambas obligatorias. Sin ajustes.
{ "id": "branch", "type": "branch_status", "x": 500, "y": 80, "status": 200 }Rama por valor
Elige Sí cuando se cumple una comparación, si no No. Sus campos y sus comparaciones son los de Comprobar valor; una comparación que no se puede hacer (lt sobre texto) falla el paso.
| Campo | En el archivo | Qué | Predeterminado | Plantillas |
|---|---|---|---|---|
| Valor | value | Lo que se compara | {{token}} | Sí |
| Condición | op | es igual a | No | |
| Esperado | expected | vacío (también si falta) | Sí |
Salidas: Sí y No, ambas obligatorias. Sin ajustes.
{ "id": "ok", "type": "branch_value", "x": 730, "y": 80, "value": "{{reply.args[0]}}", "op": "eq", "expected": "ok" }Rama paralela
Ejecuta lo que sigue a Rama 1 y Rama 2 al mismo tiempo, cada rama con su propia copia de las variables. Cada salida puede tener más cables para más ramas. Sin campos.
Salidas: Rama 1 y Rama 2, ambas obligatorias.
{ "id": "split", "type": "fork", "x": 270, "y": 80 }Unir ramas
Espera hasta que se haya alcanzado cada cable que entra en él, luego continúa una vez, con las variables de las ramas fusionadas — cuando dos ramas establecen la misma variable, gana la cuyo cable aparece más tarde en el archivo — y la última respuesta HTTP de la última de ellas que tuvo una. Sin campos.
Solo se encuentran aquí las ramas que se ejecutan todas: un Unir ramas detrás de un Rama por estado, cuyos Sí y No nunca ocurren ambos, nunca continúa; cuando ninguna otra ruta llega a Fin, la ejecución falla en este nodo, indicando cuántas ramas seguía esperando.
Salidas: Salida, obligatoria.
Cualquier otro nodo con varios cables que entran en él se ejecuta una vez por cada llegada.
{ "id": "joined", "type": "join", "x": 730, "y": 80 }Bucle
Ejecuta los pasos de Cuerpo — que vuelven a él — una y otra vez: como máximo un número de veces y, cuando tiene una condición de salida, hasta que se cumple.
| Campo | En el archivo | Qué | Predeterminado y límites | Plantillas |
|---|---|---|---|---|
| Iteraciones como máximo | max | Iteraciones como máximo | 5; 1–1 000 | No |
| detener antes si | until | Condición de salida opcional { "value", "op", "expected" }, como en Comprobar valor | desactivada | Valor y esperado: sí |
- El cuerpo siempre se ejecuta al menos una vez. La condición de salida se lee después de cada iteración, así que el cuerpo puede establecer lo que prueba.
- Hecho sigue cuando se cumple la condición — o, sin condición, tras la última iteración.
- Límite sigue cuando se agotaron las iteraciones antes de que se cumpliera la condición. Sin un cable en ella, eso falla el paso.
- Dentro del cuerpo,
{{counter}}es el número de la iteración. - Un cuerpo se ejecuta como una sola rama: cada salida dentro de él tiene un cable; no contiene Inicio, Fin, Rama paralela, Unir ramas ni otro Bucle; se entra en él solo por Cuerpo; y cada cable dentro de él conduce hacia adelante en el cuerpo o de vuelta al bucle.
Salidas: Cuerpo y Hecho (obligatorias), Límite (opcional). Sin ajustes.
{ "id": "poll", "type": "loop", "x": 270, "y": 80, "max": 10,
"until": { "value": "{{status.args[0]}}", "op": "eq", "expected": "ready" } }