# Последовательный запуск пайплайнов

Несколько компонентов `ExperimentPipeline` возможно соединить друг с другом в последовательную серию запусков, где запуск первого пайплайна предполагает последовательный запуск второго.

Если два пайплайна связаны таким образом, у пользователя появляется два варианта запуска:

- Запустить цепочку из первого и второго пайплайна вместе
- Запустить только второй пайплайн

Для соединения двух пайплайнов необходимо:

1. Добавить в манифест `ExperimentPipeline` первого пайплайна пункт `continueWith`.
2. Создать совмещённый `APIComponent` запуска цепочки, который будет соответствовать запуску первого пайплайна.

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

## Пример ExperimentPipeline

Например, в модуле есть два пайплайна. Пайплайн `part-1` содержит этап обучения модели машинного обучения. Пайплайн `part-2` содержит этап построения отчёта по обученной модели.

Первый пайплайн:

```yaml
apiVersion: "unified-platform.cs.hse.ru/v1"
kind: ExperimentPipeline
metadata:
  name: part-1
  namespace: pu-username-pa-appname
spec:
  vars:
  - name: data
  - name: model
  stages:
  - name: train
    image:
      existingImageName: platform-reg.stratpro.hse.ru/my_org/myproject-train:718e2b0
    inputs:
    - name: data
    outputs:
    - name: model
    entryPoint:
      cmd:
      - python
      - main.py
    resourceLimits:
      cpu: "500m"
      memory: "512M"
  connectedBoxes:
    - name: user-box
      path: /userdata/
      default: true
      mountS3Box:
        s3BoxName: users
  continueWith:
    name: part-2
```

Второй пайплайн:

```yaml
apiVersion: "unified-platform.cs.hse.ru/v1"
kind: ExperimentPipeline
metadata:
  name: part-2
  namespace: pu-username-pa-appname
spec:
  vars:
  - name: report_document
  - name: trained_model
  stages:
  - name: report
    image:
      existingImageName: platform-reg.stratpro.hse.ru/my_org/myproject-report:718e2b0
    inputs:
    - name: trained_model
    outputs:
    - name: report_document
    resourceLimits:
      cpu: "1"
      memory: "2G"
  connectedBoxes:
    - name: user-box
      path: /userdata/
      default: true
      mountS3Box:
        s3BoxName: users
```

Пункт `continueWith` в первом пайплайне указывает, что после завершения работы первого пайплайна автоматически вызывается второй.

## Пример APIComponent

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

Сначала, пример `APIComponent` второго пайплайна:

```yaml
apiVersion: "unified-platform.cs.hse.ru/v1"
kind: APIComponent
metadata:
  name: api-part-2
  namespace: pu-username-pa-appname
spec:
  published: true
  experimentPipeline:
    name: part-2
  restfulApi:
    auth:
      basic:
        credentials: appname-apis-cred
      identityPassThrough: true
  apiSpec:
    inputs:
      - name: trained_model
        type:
          datatypes: [ "FILE" ]
          contentTypes: [ "pth" ]
    outputs:
      - name: report_document
        type:
          datatypes: [ "FILE" ]
          contentTypes: [ "text/html" ]
```

Для второго пайплайна `APIComponent` создаётся как для обычного независимого пайплайна и содержит данные, которые пользователь передаёт на вход и получает на выход.

`APIComponent` первого пайплайна содержит данные как для себя, так и для второго пайплайна:

```yaml
apiVersion: "unified-platform.cs.hse.ru/v1"
kind: APIComponent
metadata:
  name: api-part-1
  namespace: pu-username-pa-appname
spec:
  published: true
  experimentPipeline:
    name: part-1
  restfulApi:
    auth:
      basic:
        credentials: appname-apis-cred
      identityPassThrough: true
  apiSpec:

    inputs:
      - name: data
        description: "Набор данных для обучения."
        type:
          datatypes: [ "FILE" ]
          contentTypes: [ "text/csv" ]
      - name: trained_model
        description: "Готовая модель и её конфигурация."
        type:
          datatypes: [ "FILE" ]
          contentTypes: [ "pth" ]
    outputs:
      - name: model
        description: "Готовая модель и её конфигурация."
        type:
          datatypes: [ "FILE" ]
          contentTypes: [ "pth" ]
      - name: report_document
        type:
          datatypes: [ "FILE" ]
          contentTypes: [ "text/html" ]
```

Здесь `trained_model` и `report_document` - это переменные второго пайплайна, которые не входят в первый. При получении запроса на запуск, фреймворк анализирует, какую последовательность пайплайнов нужно запустить, и отделяет переменные из `APIComponent` второго пайплайна от общего списка переменных.

На практике, если нужно передать данные из первого пайплайна во второй, для этого нужно создать две переменные с разными именами, и в запросе на запуск передать в них один и тот же путь. Тогда первый пайплайн запишет по этому пути выходные данные, а второй сможет их прочитать. В примере выше такими переменными являются `model` и `trained_model`.
