понедельник, 20 декабря 2010 г.

Как создать workflow в ODI. Часть 2.

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

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


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

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

Добавить вызов сценария в пакет можно тремя способами.
  • Добавить с панели инструментов команду OdiStartScen.

  • Перетащить сценарий из дерева компонентов проекта.

  • Сдуплицировать существующий шаг в пакете, в котором производится вызов сценария, и изменить его параметры.

Добавляемая команда запуска сценария не устанавливает значение параметра синхронности запуска сценария. По-умолчанию, если параметр не указан, ODI делает этот запуск в синхронном режиме.

Таким образом, для одновременной загрузки всех 5 таблиц справочников нам необходимо сделать 5 запусков соответствующих сценариев и установить им асинхронный режим работы.

Рассмотрим параметры команды запуска сценария.


  • Scenario Name - наименование сценария. Можно ввести самому или попробовать выбрать из списка. При большом количестве сценариев и не очень быстром доступе к репозиторию процесс такого выбора может быть достаточно долгим. А если необходимо редактировать несколько запусков сценариев, еще и утомительным, так как селект из репозитория происходит каждый раз при открытии списка сценариев.
  • Version - наименование версии сценария. Как оказалось, версия может быть не только в виде числа. Я привык работать только с версиями под номером 1, именно такое значение и ставится по-умолчанию. Если установить значение -1, будет выбран самый последний сценарий. Скорее всего, имеется ввиду сценарий с максимальной датой создания.

Следующие параметры являются опциональными.
  • Context Code - контекст выполнения сценария. Если не указано - используется тот же контекст, в котором запущена вызвавшая сценарий сессия.
  • Log Level - Уровень детальности сессии в логе выполнения. По-умолчанию устанавливается 5 - максимальный.
  • Agent Code - Наименование агента, который будет использован для запуска сценария. Если не указано - запускает тот же агент, что и в вызывающей сессии.
  • Synchronous/Asynchronous - режим работы сценария. Если не указано, сценарий вызывается синхронно, что значит, что данный шаг сессии выполнения будет завершен (успешно или неуспешно), после того, как завершится сценарий. Если указано значение Asynchronous Mode, сессия продолжит работу и перейдет к следующему шагу в цепочке выполнения.
  • Oracle Data Integrator User - имя пользователя, с использованием прав которого будет запущен сценарий, как и в остальных случаях, если не указано ничего, используется имя того пользователя, который запустил текущую сессию.
  • Oracle Data Integrator Password - пароль пользователя.
  • Session Name - наименование сессии, как оно будет отображено в логе Оператора. Если не указано - будет показано наименование сценария.
  • Keywords - перечень ключевых слов, которые будут применены к сессии этого сценария.

Сессия это процесс выполнения пакета, интерфейса, процедуры и т.п., в результате которого формируется лог этого выполнения, видимый в Операторе.


Для первого сценария я задам значения для: наименования шага пакета, синхронности/асинхронности, наименования сессии, списка ключевых слов.

Далее я буду дуплицировать шаги пакета, для того, чтобы сделать вызовы всех сценариев:


Затем через вкладку Command изменю параметры команды OdiStartScen для каждого сдуплицированного шага, это немного быстрее чем через вкладку General шага пакета. Например, для задания асинхронного режима необходимо добавить, или изменить значение параметра на такое: "-SYNC_MODE=2", а для изменения наименования сценария - подредактировать параметр "-SCEN_NAME=DICT_1".


Завершив редактирование шагов пакета, можем его запустить:


Хочу обратить внимание на такие моменты выполнения этой сессии:
  • Запускаемые из пакета сценарии отображаются в дереве выполнения как дочерние сессии (Child Sessions).
  • Несмотря на то, что 4 из 5 дочерних сессий завершились с ошибкой, главный пакет завершился успешно.
  • Главный пакет завершился успешно по той причине, что шаги главного пакета - это асинхронные вызовы сценариев, и сам вызов сценария выполнился без ошибок. Поэтому считается, что сам пакет также отработал без ошибок.
  • В логе выполнения шаги главного пакета располагаются сверху-вниз, дочерние же сессии отображаются в обратном порядке, т.е. самая первая дочерняя сессия - самая нижняя в списке.
  • Наименование дочерних сессий такое, как задано в команде запуска сценария в параметре Session Name.

При наличии дочерних сессий следить за выполнением этих сессий удобнее через закладку Hierarchical Sessions Оператора. Так как в режиме списка сессий (Session List) все запуски отображаются в виде простого одноуровневого списка.


Изменим наш пакет так, чтобы все дочерние сценарии запускались синхронно, и посмотрим на результат:


В случае синхронного выполнения дочернего сценария, шаг, который запускает сценарий, заканчивает выполнение только после того, как заканчивает выполнение дочерняя сессия. Если, при этом, дочерняя сессия заканчивается успешно, шаг пакета тоже заканчивается успешно, если же дочерняя сессия падает - шаг пакета падает, и падает сам пакет.

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


Рассмотрим параметры команды OdiWaitForChildSession:
  • Parent Session ID - идентификатор сессии, дочерние сессии которой будут контролироваться этой командой. Если не указано - работает для данной сессии. Таким образом, передав в сценарий через переменную номер сессии, можно контролировать дочерние сессии другого сценария, а не текущего. Получить же номер сессии можно через метод подстановки <%=odiRef.getSession("SESS_NO")%>
  • Polling Interval - единственный обязательный параметр. Задает интервал в секундах, по окончанию которого будет произведен запрос статуса выполнения дочерних сессий. Если сессии все еще выполняются, команда обождет очередной интервал секунд, и запросит статусы снова.
  • Name Filter - Можно указать наименование дочерней сессии, статус которой необходимо проверить. Можно даже указать некое подобие выражения, применяемого в sql операторе like. Например, если параметр задан как LOAD_%, будут проверяться все сессии, наименование которых начинается с слова LOAD, за которым идет подчеркивание, а далее любое количество символов. Обратите внимание, что речь идет именно о наименовании сессии, которое может и не совпадать с наименованием сценария.




  • Keywords - перечень ключевых слов. Данный параметр позволяет еще более гибко управлять тем, какие именно дочерние сессии будут проверяться командой. В данном случае, все перечисленные ключевые слова должны соответствовать ключевым словам в дочерних сессиях. Т.е. если здесь указать две ключевых слова, то будут проверены только те дочерние сессии, в которых заданы оба этих ключевых слова.




  • Max. Number of Failed Child Sessions - количество дочерних сессий, падение которых приведет к завершению работы команды OdiWaitForChildSession с ошибкой. По-умолчанию ставится значение ALL, что значит, что только при завершении всех дочерних сессий с ошибкой, будет также завершена с ошибкой эта команда. Обычно здесь ставится значение 1, что значит, что родительская сессия должна среагировать даже при падении хотя бы одной дочерней сессии.




Вернем асинхронный запуск дочерних сценариев загрузки в пакет, и добавим последним шагом команду OdiWaitForChildSession. Посмотрим, что изменится при запуске пакета:
Теперь пакет отработал более ожидаемо, так как при падении дочерней сессии, в нашем примере, правда, их было 4, сам пакет также завершился с ошибкой. Команда ожидания дочерних сессий падает (завершает работу с ошибкой), если выполняется условие, заданное через параметры команды. Т.е. если достаточное количество дочерних сессий с заданными именами и ключевыми словами завершились с ошибкой. В противном случае, если дочерние сессии продолжают работать или завершились успешно, команда OdiWaitForChildSession ожидает завершения работы всех дочерних сессий, подпадающих под условия и лишь затем завершится успешно в пакете. Надеюсь, после чтения этого поста станет понятен принцип, по которому можно решить следующую задачу (цитирую вопрос, вдохновивший меня на написание этих постов):
Как допустим можно выстроить параллельное выполнение 5 пакетов так, чтобы все дожидались окончания выполнения последнего и только потом начиналось выполнения следующего шага WORKFLOW?

5 комментариев:

  1. Со-читателям хочу напомнить, при передаче переменных в вызываемые сценарии, не забывать дописывать имя_проекта или GLOBAL перед названием переменной, например:

    #имя_проекта.имя_переменной

    ОтветитьУдалить
  2. VS, использовали ли Вы Keywords в OdiWaitForChildSession? Интересно было бы увидеть примеры использования. Спасибо!

    ОтветитьУдалить
  3. Если я ничего не путаю, то нет, мне пока не приходилось использовать ключевые слова в этой команде.
    Теоретически, как мне видится, использование ключевых слов для фильтрации списка сессий, окончание которых проверяется, - это редкие случаи написания неких фреймворков для загрузки данных.
    В этом случае, может сложиться такая ситуация, когда не очень удобно или совсем невозможно, фильтровать сессию по, например, первым нескольким символам.
    В таком случае всем сессиям назначается одно и тоже ключевое слово, и OdiWaitForChildSession ждет выполнения только заключёванных сессий.

    Еще один момент, на который возможно, не все обратили внимание в посте: OdiWaitForChildSession - не пускает процесс выполнения дальше, пока не случится либо завершение, либо падение всех сценариев. Нельзя составить последовательность шагов ожидания, чтобы по этой последовательности шел процесс выполнения, а в зависимости от заданных ключевых слов срабатывала та или иная команда OdiWaitForChildSession.

    ОтветитьУдалить
  4. Насколько я понял из описания, SESSION_KEYWORDS позволяет выбирать, окончание каких именно сессий мы ожидаем (http://gerardnico.com/doc/odi/webhelp/en/ref_tools/snpswaitforchildsession.htm):

    Examples
    Waits, with a polling interval of 5 seconds, for all the child sessions of the current session named like "LOADxxx" and having the keywords "MANDATORY" and "CRITICAL", to be finished

    OdiWaitForChildSession -PARENT_SESS_NO=<%=odiRef.getSession("SESS_NO")%> -POLL_INT=5 -SESSION_NAME_FILTER=LOAD% -SESSION_KEYWORDS=MANDATORY,CRITICAL

    ОтветитьУдалить
  5. ... что открывает интересные возможности для синхронизации нескольких сценариев.

    ОтветитьУдалить