Перейти к содержимому

Запуск эксперимента ​

Чтобы выполнить эксперимент на сервере из скрипта или конвейера и узнать, чем всё закончилось, отправьте его на POST /api/run. Сервер доводит запуск до конца и отвечает результатом — а если вы попросите, то и каждым шагом по мере его выполнения. Именно этим пользуется signallab run --server.

Это тот же запуск, что и по кнопке Запустить редактора и через experiment_start: задача, которую видит и может остановить каждая открытая страница, те же события, тот же отчёт в папке данных.

Запрос ​

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 }

Тело называет один эксперимент — document или template, но не оба сразу — и то, с чем его запускать:

ПолеТипПо умолчаниюЗначение
documentобъект—Эксперимент в том виде, как его сохраняет и экспортирует редактор. Старые версии переносятся на текущую, как при открытии файла
templateстрока—Встроенный шаблон по имени файла, с .json или без (ниже)
overridesобъект{}Значения параметров только для этого запуска. Значения могут быть строками, числами или логическими; каждое должно быть параметром эксперимента
profileстрокапрофиль документаЗапустить с этим профилем; "" запускает со значениями по умолчанию
seedчислоseed документа, иначе новыйОт 0 до 9007199254740991; один и тот же seed даёт одни и те же случайные значения
timeoutчисло300Секунд до того, как запуск завершится ошибкой run.timeout; от 1 до 300

Поле, которого сервер не знает, отклоняется (400, api.run_invalid). Сам документ читается так же, как открываемый файл, поэтому он не больше 4 МиБ.

Встроенные шаблоны — эксперименты, которые редактор предлагает в разделе Шаблоны:

templateЧто это
emptyСтарт и финиш
http-checkGET на http://127.0.0.1:8080/, затем проверка статуса 200
status-branchGET на http://127.0.0.1:8080/; при 200 — сообщение OSC, иначе пауза 500 мс
parallel-flowsУзел Параллельный запуск на GET http://127.0.0.1:8080/ и запись в журнал, рядом друг с другом, затем узел Слияние потоков
osc-ping-replyOSC /ping на параметр device (127.0.0.1:9000), затем ожидание 2 с /pong на 127.0.0.1:9001
poll-until-readyУзел Цикл, который спрашивает device по OSC о /status, пока тот не ответит ready, не больше 10 раз
flaky-apiЭмулированный API (параметр api), который сначала даёт сбои, а потом работает; его опрашивает узел Цикл, пока он не ответит 200
fault-phasesУстройство UDP за реле помех, на которое отправляют 8 с, пока реле становится чистым, с потерями, отключённым и снова чистым
dependency-outageЭмулированный API (параметр api), отключённый на 2 с, пока узел Цикл опрашивает его, пока он снова не ответит 200
websocket-echoСоединение с параметром service (ws://127.0.0.1:9001/echo), сообщение, ожидание его эха, проверка, закрытие

Откройте любой из них в разделе Шаблоны, чтобы увидеть его узлы и параметры; см. эксперименты.

Результат ​

По умолчанию ответ — 200 с Content-Type: application/json, отправленный, когда запуск закончился: один объект JSON, результат запуска.

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"
}
ПолеТипЗначение
job_idчислоЗадача запуска
experimentстрокаИмя эксперимента
outcomeстрокаpassed, failed или stopped
seedчислоseed, с которым он работал: передайте его обратно как seed, чтобы получить те же значения
profileстрока или nullПрофиль, с которым он работал
overriddenлогическоеЧасть значений пришла из overrides
paramsобъектВсе значения параметров, которые использовал запуск
started_ms, ended_msчислоМиллисекунды с 1970 года
errorEngineErrorПочему он не прошёл: его первый сбой. Пропускается, если он прошёл
stepsobject[]Все шаги в порядке выполнения, как у experiment://step
emulatorsobject[]Что принял и на что ответил каждый узел Эмулятор: node, name, protocol, local, counts. Пропускается, если таких нет
impairmentsobject[]Что сделало реле каждого узла Сетевые помехи по фазам. Пропускается, если таких нет
report_pathстрокаОтчёт запуска на сервере; скачайте его через /api/files. Пропускается, если отчёт не записан
report_errorEngineErrorПочему отчёт не удалось записать. Иначе пропускается

Значения секретов маскируются во всём этом. В файле отчёта те же шаги; см. запуски и отчёты.

Пока запуск идёт, сервер каждые 15 с отправляет пробел. JSON игнорирует пробелы перед значением, поэтому результат по-прежнему разбирается, а прокси не принимает долгий тихий запуск за разорванное соединение.

Следим за шагами ​

Чтобы видеть шаги по мере их выполнения, запросите NDJSON:

http
Accept: application/x-ndjson

Ответ — 200 с Content-Type: application/x-ndjson: по одному объекту JSON на строку, у каждого есть type.

typeКогдаОстальное в строке
startedПервой, один разjob_id, experiment, seed, profile, overridden, started_ms
stepНа каждый шагШаг, как у experiment://step
heartbeatКаждые 15 сНичего
endedПоследней, один разРезультат, как выше
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"}

Читайте строки до ended; незнакомый type игнорируйте. Сервер отправляет X-Accel-Buffering: no, поэтому прокси nginx передаёт каждую строку сразу.

Статус и исход ​

Статус ошибки HTTP означает, что запуск не начался; тело — это EngineError:

СтатусКодПочему
400api.run_invalidТело — не запрос на запуск: не JSON, неизвестное поле, переопределение не строка, не число и не логическое
400api.run_sourceНет ни document, ни template, или есть оба
415command.json_requiredНе Content-Type: application/json
422api.template_unknownВстроенного шаблона с таким именем нет
422file.json_invalid, file.too_large, doc.*Документ не удаётся прочитать
422любой код проверки, run.override_unknown, profile.active_missing, run.limit_range, seed.range, secret.missing, transport.address_in_use…Эксперимент не может начаться: он не проходит проверку, значение вне диапазона, секрет не сохранён, порт, который он слушает, занят

Как только запуск начался, статус всегда 200, что бы ни случилось: читайте outcome в результате.

outcomeЗначение
passedВсе шаги прошли, и достигнут узел Финиш
failedШаг не прошёл или запуск шёл дольше своего timeout (run.timeout); error говорит, какой и почему
stoppedЕго остановили до конца: через job_stop, Остановить всё или при остановке сервера. В steps — шаги, до которых он дошёл; отчёт не сохраняется

Клиент пропал ​

Закрытое соединение запуск не останавливает. Это задача на сервере: она доходит до конца и сохраняет отчёт, как запуск из браузера при закрытой вкладке. Найдите её через jobs_list, остановите через job_stop, а отчёт потом прочитайте через experiment_runs. Когда сервер останавливается, запуск прерывается, а подключённый клиент получает "outcome": "stopped".

Примеры ​

Выполнить встроенный шаблон и дождаться исхода:

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

Отправить собственный эксперимент с изменённым параметром и печатать каждый шаг по мере выполнения:

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 не даёт curl придерживать строки. Чтобы конвейер завершался ошибкой при неудавшемся запуске, проверяйте 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" ]

Из командной строки ​

signallab run с --server <url> выполняет запуск на сервере через этот эндпоинт: он отправляет прочитанный эксперимент вместе с overrides, seed и timeout, запрашивает NDJSON и печатает каждый шаг, как только приходит его строка. Токен берётся из --token-file, иначе из SIGNALLAB_TOKEN. С --report он скачивает отчёт через /api/files. Сервер, который молчит 60 с — даже без heartbeat, — считается пропавшим.