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

Рабочие процессы Pro

Рабочие процессы (Workflows) позволяют объединить несколько шаблонов задач в направленный граф (DAG) с ветвлением, согласованиями и паузами по времени. Выполнение рабочего процесса продвигается автоматически по мере завершения шагов: граф создаётся один раз в визуальном редакторе, после чего запуски выполняются со страницы Workflows.

к сведению

Рабочие процессы — функция Semaphore Pro. Пункт меню Workflows появляется только в том случае, если ваша подписка её включает.

Обзор​

Рабочий процесс состоит из:

  • Узлов — шагов графа (запуск шаблона, ожидание согласования, пауза на заданное время или заметка).
  • Рёбер — связей между узлами; у каждой связи есть условие, определяющее, когда запускается следующий узел.

При запуске рабочего процесса Semaphore создаёт выполнение рабочего процесса (workflow run). Продвижением управляет сервер: по мере завершения задач, получения согласований или истечения пауз запускаются следующие узлы в соответствии с условиями рёбер.

Создание рабочего процесса​

  1. Откройте проект и перейдите в раздел Workflows.
  2. Нажмите New Workflow.
  3. В графическом редакторе:
    • Перетащите узлы из палитры на холст.
    • Соедините узлы, перетащив связь от выходной точки одного узла к другому.
    • Щёлкните по узлу или ребру, чтобы изменить его свойства на боковой панели.
  4. Задайте имя (и при необходимости начальную версию для нумерации запусков).
  5. Устраните все проблемы из панели Problems и нажмите Save.

Редактор рабочих процессов

Перед сохранением редактор проверяет граф. Корректный рабочий процесс должен содержать хотя бы один узел, ровно один начальный узел (без входящих рёбер), не иметь циклов и иметь полную конфигурацию у каждого исполняемого узла.

Типы узлов​

ТипНазначение
TaskЗапускает шаблон задачи. Параметры шаблона (инвентарь, окружение, ограничение Ansible limit, дополнительные аргументы командной строки) можно переопределить для каждого узла через task params.
ApprovalПриостанавливает выполнение до тех пор, пока пользователь с соответствующим правом не подтвердит или не отклонит его. При необходимости задаются таймаут (в секундах) и текст запроса согласования.
DelayОжидает заданное число секунд перед переходом к следующим узлам. Полезно для выдержки времени, окон обслуживания или разнесения зависимых шагов.
NoteПроизвольная заметка на холсте. Узлы Note не выполняются и не соединяются рёбрами — они нужны только для документирования.

Схождение​

Узлы с несколькими входящими рёбрами могут требовать завершения всех предыдущих узлов (по умолчанию) или любого из них. Задайте параметр Convergence на панели свойств узла.

Узлы задержки​

Узел задержки приостанавливает выполнение рабочего процесса на заданное время (минимум 1 секунда). Во время ожидания:

  • Выполнение остаётся в статусе running.
  • В окне выполнения на узле задержки отображается обратный отсчёт.
  • Следующие узлы, соединённые рёбрами, не запускаются, пока задержка не завершится.

Если выполнение рабочего процесса остановлено во время активной задержки, задержка отменяется, а выполнение завершается со статусом stopped.

Узлы согласования​

Когда выполнение доходит до узла согласования, статус меняется на approval до тех пор, пока кто-либо не подтвердит или не отклонит его. Кнопки Approve и Reject отображаются в окне выполнения. Отклонённое согласование приводит к сбою выполнения в соответствии с условиями присоединённых рёбер.

Условия рёбер​

У каждого ребра есть условие, определяющее, когда следующий узел становится готовым к запуску:

УсловиеСледующий узел запускается, когда предыдущий…
On successЗавершился успешно (по умолчанию).
On failureЗавершился с ошибкой.
AlwaysЗавершился в любом конечном состоянии (успех или ошибка).

Используйте ветви On failure для компенсирующих действий или уведомлений. Используйте Always, когда следующий шаг должен выполняться независимо от результата.

Запуск и наблюдение​

  • Run workflow — запускает новое выполнение из списка Workflows.
  • Окно выполнения — полноэкранный граф с текущим статусом каждого узла (running, success, failed, approval, обратный отсчёт задержки).
  • Stop — пока выполнение находится в статусе running или approval, пользователи с правом run_project_tasks могут его остановить. Все активные задачи останавливаются, ожидающие согласования отклоняются, а выполнение помечается как stopped.

Статусы выполнения: running, approval, success, failed, stopped.

Нумерация версий запусков​

Задайте Start version для рабочего процесса (например, 1.0.0), чтобы включить метки версий у каждого запуска. Semaphore увеличивает версию при последующих запусках — так же, как для шаблонов сборки.

Выходные и входные данные​

Узел задачи может передавать структурированные данные следующим за ним узлам. Задача создаёт выходные данные (outputs): JSON-объект именованных значений, который сохраняется вместе с задачей при её успешном завершении. Связь, ведущая в следующий узел задачи, доставляет входные данные (inputs): она заполняет survey-переменные шаблона этого узла из выходных данных предыдущего узла. Файлы не передаются — только значения.

Создание выходных данных​

Каждая задача, запущенная выполнением рабочего процесса, получает переменную окружения SEMAPHORE_OUTPUTS_FILE: путь к пустому файлу, созданному только для этой задачи. Всё, что задача запишет туда в виде JSON-объекта, становится её выходными данными.

ПриложениеКак создаются выходные данные
Ansibleansible.builtin.set_stats с per_host: false (по умолчанию). Встроенный callback-плагин semaphore_outputs записывает в файл агрегированную статистику запуска; статистика по отдельным хостам выходными данными не является.
Terraform, OpenTofu, TerragruntЗахватываются автоматически из output -json после успешного запуска. Значение, которое задача сама записала в файл, имеет приоритет над захваченным output с тем же именем.
Bash, Python, PowerShell, PulumiСкрипт сам записывает файл.
# Bash: запись файла выходных данных
cat > "$SEMAPHORE_OUTPUTS_FILE" <<EOF
{"image_tag": "1.4.2", "replicas": 3, "subnet_ids": ["subnet-1", "subnet-2"]}
EOF
# Ansible: set_stats становится выходными данными
- name: Publish the image tag for the next nodes
ansible.builtin.set_stats:
data:
image_tag: "{{ built_tag }}"

Правила:

  • Выходные данные читаются, только если задача завершилась успешно. У задачи, завершившейся с ошибкой или остановленной, их нет, поэтому ветвь On failure ничего не получает от упавшего узла.
  • Имена выходных данных соответствуют ^[A-Za-z_][A-Za-z0-9_-]*$. Значением может быть любое значение JSON: строка, число, логическое значение, список или объект.
  • Ограничения: размер файла — не более 256 КБ, не более 100 выходных значений размером не более 32 КБ каждое.
  • Отсутствующий или пустой файл означает «нет выходных данных». Файл, который не является JSON-объектом, содержит недопустимое имя или нарушает ограничение, приводит к ошибке задачи, причина указывается в её логе.
  • Outputs Terraform, которые невозможно сохранить (помеченные как sensitive, слишком большие, с недопустимым именем или сверх ограничений), пропускаются и перечисляются в логе задачи и на панели Outputs задачи как Not captured. Они никогда не приводят к ошибке задачи.

Доставка входных данных​

Щёлкните по связи, которая заканчивается в узле задачи: на её боковой панели есть раздел Inputs.

  • По имени (по умолчанию). Каждое выходное значение исходного узла, имя которого совпадает с survey-переменной целевого шаблона, заполняет эту переменную. Выходные значения без соответствующей переменной игнорируются; output Terraform с дефисом в имени никогда не является допустимым именем переменной, поэтому не доставляется.
  • Map inputs explicitly. Установите флажок, чтобы доставлять только перечисленные вами пары: survey-переменную целевого шаблона и ключ выходных данных, который её заполняет. Пустой список ничего не доставляет. Когда у рабочего процесса есть завершённый запуск, панель подсказывает ключи, созданные этим запуском, и помечает ключ, который не был захвачен.

Переменная, которую не заполнила ни одна связь, берёт значение, заданное в узле, а затем значение по умолчанию переменной. Если обязательная переменная осталась без значения, задача узла завершается с ошибкой ещё до старта, а строка лога называет эту переменную, поэтому запуск идёт по переходам On failure.

Значения приводятся к типу переменной: переменная int принимает число или строку из цифр, переменная enum или select — только свои варианты, переменная string или text — что угодно (объект или список приходят в виде компактного JSON). Неподходящее значение игнорируется, причина записывается в лог задачи, и применяется запасное значение.

Узлы согласования и задержки пропускают выходные данные дальше: цепочка task → approval → task по-прежнему доставляет данные, и действует режим последней связи.

Несколько связей в один узел. Вклад вносит каждая связь, исходный узел которой завершился успешно. Если две из них заполняют одну и ту же переменную, явное сопоставление имеет приоритет над доставкой по имени; из двух связей одного вида побеждает созданная раньше, поэтому запуск каждый раз даёт один и тот же результат. Лог задачи называет победившую связь.

The connection panel in by-name mode: matched survey variables are ticked

The connection panel with explicit mapping: one output key per survey variable

Где их посмотреть​

  • В окне выполнения на каждом узле, создавшем выходные данные, отображается бейдж N outputs.
  • В диалоге задачи есть таблица Outputs со значениями и списком Not captured.
  • Лог задачи, получившей данные по связи, начинается с отдельной строки для каждой переменной, например Input "image_tag" <- output "image_tag" of node 3 (task #41), так что источник каждого значения указан строкой выше самого значения.

Run view: nodes that produced outputs carry a badge

Task dialog, Details tab: the Outputs table

Ограничения​

  • Выходные данные хранятся и отображаются в открытом виде для всех, кто может видеть задачу. Не передавайте секреты через выходные данные. Survey-переменную типа secret нельзя заполнить через связь.
  • Выходные данные — это значения, а не код: Ansible получает их как буквальные строки, и выражение Jinja2 внутри значения не вычисляется.
  • Задачи на удалённых раннерах создают и получают выходные данные так же, как задачи на сервере. Задачи, выполняемые исполнителем Docker или Kubernetes раннера, пока не создают выходных данных; об этом сообщается в их логе.

Переменные окружения​

Задача, запущенная рабочим процессом, получает дополнительно к переменным, доступным каждой задаче:

ПеременнаяЗначение
SEMAPHORE_WORKFLOW_IDID рабочего процесса
SEMAPHORE_WORKFLOW_RUN_IDID текущего запуска
SEMAPHORE_WORKFLOW_VERSIONВерсия текущего запуска, если она задана
SEMAPHORE_WORKFLOW_URLСсылка на страницу запуска, например https://semaphore.example.com/project/1/workflows/7/runs/42 (требуется web_host в конфигурации сервера)
SEMAPHORE_OUTPUTS_FILEПуть к файлу, в который задача записывает свои выходные данные

Эти переменные задаются для всех приложений, включая Ansible и Terraform, и доступны задачам, выполняющимся на удаленных runner-ах.

Права доступа​

  • Управление рабочими процессами (создание, изменение, удаление) требует прав на управление ресурсами проекта.
  • Запуск рабочих процессов требует права run_project_tasks.
  • Обработка согласований требует соответствующего доступа к проекту (те же пользователи, которые могут запускать задачи в проекте).

API​

Шаблоны рабочих процессов и их выполнения доступны по пути /api/project/{project_id}/workflows. Схемы запросов и ответов, включая поля узла delay (delay_seconds), поля input_mode и input_mappings у рёбер, документ artifacts каждой задачи в деталях запуска (GET …/runs/{run_id}) и эндпоинт остановки (POST …/runs/{run_id}/stop), описаны в документации API.