# Урок 22. Запуск графов по расписанию

{% include [note-alert](../_includes/onboarding-alert.md) %}

> Перед началом урока заведите себе папку для экспериментов `yourStaffLogin` в [/onboarding/playground](https://nirvana.yandex-team.ru/browse/resolve?path=%2Fonboarding%2Fplayground). Вся дальнейшая работа с сущностями в уроке будет вестись в ней.

## Шаг 1. Настроим запуск графа по расписанию {#regularize}

Регулярность запуска графа обеспечивает [Реактор](https://wiki.yandex-team.ru/nirvana/reactor). В этом шаге мы настроим простой процесс в Реакторе (именуемый *реакцией*), обеспечивающий запуски шаблонного графа по расписанию без дополнительной параметризации.

1. В качестве подготовки (и чтобы не засорять [демонстрационный граф](https://nirvana.yandex-team.ru/flow/13689131-d174-4c8f-bdd7-7b3032e2b4b1/538a726f-992d-4049-96e5-168253c6c2c2/graph)) склонируем его в воркфлоу в свою папку для экспериментов. Или можно для экспериментов использовать уже имеющийся в своей папке граф.

   {% cut "Напомним, как это сделать." %}

   В хотбаре сверху справа ховер по `Clone` -> `Clone to...`.

   ![https://jing.yandex-team.ru/files/babichev-av/cron_step0_cloneTo.png](https://jing.yandex-team.ru/files/babichev-av/cron_step0_cloneTo.png)

   В открывшемся диалоге выбираем `Existing Workflow` (если у вас уже есть подходящий, в этом случае выбираем его) или `New Workflow` (если такой нужно создать, в этом случае выбираем папку и задаем имя нового воркфлоу), после чего кликаем в `Clone`.

   ![https://jing.yandex-team.ru/files/babichev-av/cron_step0_newWF-1.png](https://jing.yandex-team.ru/files/babichev-av/cron_step0_newWF-1.png)

   В открывшемся редакторе склонированного графа не забываем сохранить новый драфт, кликнув в `Save` в хотбаре сверху справа.

   ![https://jing.yandex-team.ru/files/babichev-av/cron_step0_save.png](https://jing.yandex-team.ru/files/babichev-av/cron_step0_save.png)

   {% endcut %}

2. На странице графа в хотбаре сверху слева откроем панель автоматизации (`automation panel`, иконка колбочки).Слева откроется панель со списком настроенных на запуск графа реакций.В свежесозданном воркфлоу не будет никаких реакций (в демонстрационном графе будут ссылки на демонстрационные реакции из этого и других уроков).

    ![https://jing.yandex-team.ru/files/babichev-av/cron_step1_automation.png](https://jing.yandex-team.ru/files/babichev-av/cron_step1_automation.png)

3. Создадим реакцию, кликнув в `Add Reaction...`.Откроется предзаполненный диалог создания реакции (такой же точно, как и при создании реакции из интерфейса Реактора, только с уже подставленной частью настроек).

    ![https://jing.yandex-team.ru/files/babichev-av/cron_step2_form.png](https://jing.yandex-team.ru/files/babichev-av/cron_step2_form.png)

4. Выберем имя реакции и нужный путь (по умолчанию реакция будет создана в домашней папке с именем, совпадающим с именем воркфлоу).

    ![https://jing.yandex-team.ru/files/babichev-av/cron_step3_name.png](https://jing.yandex-team.ru/files/babichev-av/cron_step3_name.png)

5. При необходимости можно поменять [проект](https://wiki.yandex-team.ru/nirvana/reactor/project/) (отвечающий за используемые реакцией [ресурсы](https://wiki.yandex-team.ru/nirvana/reactor/project/quota/)) и [ttl на запуски реакций](https://wiki.yandex-team.ru/nirvana/reactor/project/quota/#ttl) (по умолчанию выбраны ваш персональный проект и ttl в 30 дней). В рамках урока хватит дефолтных значений.

   ![https://jing.yandex-team.ru/files/babichev-av/cron_step4_project.png](https://jing.yandex-team.ru/files/babichev-av/cron_step4_project.png)

6. Добавим реакции источник событий для запуска aka [триггер](https://wiki.yandex-team.ru/nirvana/reactor/reaction/trigger/).Если коротко, триггер описывает, при наступлении каких событий необходимо пытаться запустить реакцию. Каждая реакция должна иметь не менее одного триггера.Триггеры в Реакторе бывают 2 типов - по событию (aka `Artifact trigger`) и по расписанию (aka `CRON trigger`). В данном уроке мы настраиваем запуск графа по расписанию, так что нужен кроновый триггер (про артефактные триггеры рассказ будет в уроке ["Запуск графов по событию"](https://wiki.yandex-team.ru/nirvana/dev/onboarding-nirvana-q32021/regular-launches-by-event/).Кроновый триггер описывается кроновым выражением и политикой обработки пропусков (пропуски неизбежно появляются, так как могут быть сетевые проблемы / задержки между запусками обработчика триггеров).[Подробнее о кроновых триггерах.](https://wiki.yandex-team.ru/nirvana/reactor/reaction/trigger/cron/)Выберем уникальное (желательно, описательное) имя триггеру и кроновое выражение `0 30 8 * * ?`, соответствующее запуску в 8:30:00 каждого дня (это отразится на расшифровке под введенным выражением). Политику обработки пропущенных моментов времени оставим по умолчанию (дефолт `Fire all` означает, что если Реактор обнаружит, что прошляпил запуски за какие-то моменты времени, он сразу же запустит реакцию за каждый пропущенный подходящий под расписание момент времени).

    ![https://jing.yandex-team.ru/files/babichev-av/cron_step5_trigger.png](https://jing.yandex-team.ru/files/babichev-av/cron_step5_trigger.png)

7. Реактор запускает графы в Нирване путем клонирования графа-источника и запуска полученных клонов.В параметрах реакции уже предзаполнен граф-источник (это граф, запуск которого мы регуляризуем) и автор создаваемых клонов (по умолчанию это пользователь). Создаваемые клоны по-умолчанию будут попадать в тот же воркфлоу, где находится граф-источник. При желании можно настроить складывание клонов в отдельный воркфлоу (добавив ссылку на него в опциональный параметр `Target Workflow ID`, который можно добавить на форму создания реакции через нав. панель в правой части формы, в нав. панели есть поиск).
   > Если вы решили запуски хранить в том же воркфлоу, где и граф-источник (т.е. не задавать `Target Workflow ID`), мы настоятельно рекомендуем выставить в воркфлоу тип смены main-версии графа с `Auto` на `Manually`. В противном случае каждый новый запуск Реактором будет становиться новым mainом, что усложнит вам поддержку процесса. Сделать это можно в диалоге редактирования воркфлоу (в хотбаре `Workflow Details` -> `Edit` -> `How to update Main Instance`)Запуски, созданные автоматикой, можно скрыть, убрав галочку `API launches` в панели со списокм графов.
   В реакции мы не будем менять параметры реакции. Входы и выходы наш граф (в рамках поставленой задачи) также не имеет, так что входы/выходы в реакции задавать тоже не будем. Осталось кликнуть в `Automate`, и мы почти у цели!

    ![https://jing.yandex-team.ru/files/babichev-av/cron_step6_trigger.png](https://jing.yandex-team.ru/files/babichev-av/cron_step6_trigger.png)

8. В списке реакций появилась созданная нами реакция. Но она выключена (т.е. сразу запуски не начнут появляться) - ее статус сразу после создания INACTIVE. Осталось последнее - включить созданную реакцию. Для этого наведем на созданную реакцию в панели курсор и в выпавшем окошке кликнем в `Activate`.

    ![https://jing.yandex-team.ru/files/babichev-av/cron_step7_activate.png](https://jing.yandex-team.ru/files/babichev-av/cron_step7_activate.png)

  Статус реакции сменится на ACTIVE.

    ![https://jing.yandex-team.ru/files/babichev-av/cron_step7_active.png](https://jing.yandex-team.ru/files/babichev-av/cron_step7_active.png)

9. Готово! Вы восхитительны :)

## Шаг 2. Поменяем расписание. {#change-schedule}

Допустим, мы хотим поменять время срабатывания графа с 8:30:00 каждого дня на 18:00:00 только по будням. В этом шаге мы поменяем триггеры реакции, созданной на предыдущем шаге, настроив выражение для запуска по новому расписанию.

Для этого нам придется провалиться в полноценный UI Реактора.

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

    ![https://jing.yandex-team.ru/files/babichev-av/cron_2_step1_reaction.png](https://jing.yandex-team.ru/files/babichev-av/cron_2_step1_reaction.png)

2. В Реакторе триггеры представляют собой отдельную от реакции сущность со своим жизненным циклом. То есть можно менять множество триггеров, не меняя настройки непосредственно самой реакции. При этом в Реакторе по отношению к триггерам действует два инварианта: **триггер после своего создания неизменяем** и **у реакции в любой момент есть как минимум один триггер**. Заметим, что в единственном триггере  кнопка удаления (мусорка) неактивна.Поэтому необходимо сперва создать новый триггер, а после этого удалить старый.Добавим новый кроновый триггер в реакции, кликнув в `Add trigger`.

    ![https://jing.yandex-team.ru/files/babichev-av/cron_2_step2_newTrigger.png](https://jing.yandex-team.ru/files/babichev-av/cron_2_step2_newTrigger.png)

  В открывшемся диалоге дадим новому триггеру уникальное (в пределах реакции) имя и новое выражение `0 0 18 ? * MON,TUE,WED,THU,FRI`, соответствующее запуску в 18:00:00 каждый будний день (это отразится в описании под введенным выражением), после чего кликнем в `Add trigger`.

   ![https://jing.yandex-team.ru/files/babichev-av/cron_2_step2_newCron.png](https://jing.yandex-team.ru/files/babichev-av/cron_2_step2_newCron.png)

  В реакции будет добавлен новый триггер, который займет место рядом с существующим.

3. Осталось включить новый триггер и выключить старый.
   > Рекомендуем обновлять кроновый триггер в момент между предполагаемыми запусками, чтобы избежать дублирования или пропусков в обработке (Misfire policy работает только с момента активации триггера.
   Для этого кликнем в `pause` в активном старом триггере и в `play` в свежесозданном неактивном триггере (в желаемом порядке).

   ![https://jing.yandex-team.ru/files/babichev-av/cron_2_step3_activate.png](https://jing.yandex-team.ru/files/babichev-av/cron_2_step3_activate.png)

   После этого триггеры изменят свой статус: старый станет неактивен, а новый, наоборот, активируется.

4. Последним шагом можем удалить старый триггер. Кнопка "мусорка" у обоих триггеров будет активной, так как после удаления любого из них останется второй.В демонстрационной реакции старый триггер не удален.**Удалять можно только неактивные триггеры!**

5. Готово! Вы восхитительны вдвойне :)

## Шаг 3. Добавим параметризацию запусков. {#parameterize}

Допустим, мы хотим, чтобы в нашем примере к нам каждый четный день в письме обращались "Сашка", а каждый нечетный - "Александр". Для этого необходимо параметризовать запуски, создаваемые Реактором.В этом шаге расширим описание кронового триггера, добавив примитивную параметризацию для запускаемых графов. Для этого нам тоже потребуется полноценный UI Реактора, который мы коснулись в прошлом шаге.Поскольку передаваемый из Реактора параметр нужно как-то передать в граф, а в уже настроенной реакции никаких входов граф не принимает, обновлением триггера мы уже не сможем обойтись. Нам необходимо изменить реакцию, добавив в нее вход.
> Изенить реакцию можно, заменив текущую версию реакции новой. Замену можно производить только тогда, когда все триггеры реакции неактивны. При замене реакции нужно учитывать, что запуски старой версии реакции будут привязаны к этой старой версии. Это же касается и триггеров. В целом при замене произойдет следующее: старая версия реакции депрецирутся, ее триггеры потеряют возможность быть активированными снова, бегущие запуски продолжат бежать, новые запуски перестанут появляться, будет создана новая версия реакции с новыми триггерами на основе заполненной формы. После чего в карточке реакции появится сверху справа селектор версий реакции (для возможности увидеть старые версии и их запуски).
В уроке мы заменим реакцию, но для удобства демонстрационную версию реакции мы оставили нетронутой (создав в качестве новой версии полноценную реакцию рядом)

1. Выключим все активные триггеры реакции, кликнув в `Deactivate all`.

    ![https://jing.yandex-team.ru/files/babichev-av/cron_3_step1_deactivate.png](https://jing.yandex-team.ru/files/babichev-av/cron_3_step1_deactivate.png)

2. Начнем замену реакции, кликнув в `Update` в хотбаре.Откроется форма обновления реакции, похожая на форму создания реакции. Отличия только в том, что тут нельзя задать имя реакции, можно выбрать режим замены и указать для себя комментарий, почему производим замену реакции.

    ![https://jing.yandex-team.ru/files/babichev-av/cron_3_step2_update.png](https://jing.yandex-team.ru/files/babichev-av/cron_3_step2_update.png)

3. При обновлении реакции сбрасывается ttl на запуски (извините, починим), поэтому стоит вернуть ttl на место. Для этого в нав. панели добавим на форму опциональный параметр `Instance TTL` и определим его нужным значением (до обновления это было 30 дней).

    ![https://jing.yandex-team.ru/files/babichev-av/cron_3_step3_returnTtl.png](https://jing.yandex-team.ru/files/babichev-av/cron_3_step3_returnTtl.png)

4. Проверку четности дня мы будем проводить в [выражении](https://wiki.yandex-team.ru/nirvana/reactor/expression/) триггера. Выражение позволяет более гибко настроить реакцию, позволяя определять вычисляемые в динамике значения, которые затем можно пробрасывать во входы реакции.В триггере `every_weekday_evening` добавим следующее выражение:
   ```
   var day = Context.cronScheduledTime().day;
   global nickname = day % 2 == 1 ? "Сашка" : "Александр";
   ```
   В нем мы определяем строковую глобальную переменную `nickname`, в которую в рантайме будет попадать значение в зависимости от времени срабатывания по расписанию, заданному кроновым выражением.

   ![https://jing.yandex-team.ru/files/babichev-av/cron_3_step4_expression.png](https://jing.yandex-team.ru/files/babichev-av/cron_3_step4_expression.png)

5. В графе обращение в письме задается глобальной опцией `nickname` графа. Добавим в реакции вход, который будет пробрасывать значение из Реактора в нужную глобальную опцию.В нав. панели добавим нужный вход: `Inputs` -> `Global parameters` -> клик в `+` у `What do your friends...`.В форме появится окно ввода для входа с селектором способа указания значения. Для проброса значения из глобальной переменной, определенной в выражении, выбираем способ `Variable`, после чего по клику в поле ввода саджест предложит на выбор одну из объявленных в реакции глобальных переменных. У нас это единственная переменная `nickname`, которую мы и выберем.

    ![https://jing.yandex-team.ru/files/babichev-av/cron_3_step5_input.png](https://jing.yandex-team.ru/files/babichev-av/cron_3_step5_input.png)

6. Наконец, по желанию укажем коммент для истории и кликаем `Save`. Почти готово!

    ![https://jing.yandex-team.ru/files/babichev-av/cron_3_step6_confirm.png](https://jing.yandex-team.ru/files/babichev-av/cron_3_step6_confirm.png)

7. В обновившейся карточке реакции справа сверху появился селектор версий с выбранной последней версией. Нам осталось только включить триггер у новой версии реакции, кликнув в `play` у триггера.

    ![https://jing.yandex-team.ru/files/babichev-av/cron_3_step6_activate.png](https://jing.yandex-team.ru/files/babichev-av/cron_3_step6_activate.png)

8. Вот и все!
