Oozie Workflow Pattern 3

이전 포스트에는 Oozie의 워크플로우 패턴중 하나인 fork-and-join 패턴에 관해서 알아보았습니다. 이번 시간에는 워크플로우 내에 액션의 결과에 조건을 주어 다음 액션을 어디로 수행할 것인지 결정할 수 있는 capture-and-decide 패턴에 대해 알아보도록 하겠습니다.

capture-and-decide pattern

capture-and-decide 패턴이라고 하니까 약간 어려운 느낌이 있지만 실제로는 간단한 패턴이죠. 앞서 수행된 액션에서 저장된 결과를 아웃풋으로 전달해주고 다음 액션에서는 해당 아웃풋을 받아서 어떠한 액션을 수행할 것인지 결정하게 되는 것이죠. 즉 간단한 제어문이라고 볼 수 있겠습니다. if-else 패턴이라고도 할 수 있겠네요.

어디서 많이 본 형태의 그림인거 같죠? 순서도(flowchart)에서 참 거짓에 따라 수행하는 로직이 달라지는 형태와 같습니다. 앞의 자바 액션의 검사 결과를 바탕으로 데이터가 있는지 체크 후에 데이터 유무에 따라 서로 다른 액션을 수행하는 경우 사용됩니다. 그럼 workflow.xml을 어떤식으로 작성하는지 알아볼까요?

<workflow-app name="validation" xmlns="uri:oozie:workflow:0.4">

   <global>
         <job-tracker>${jobTracker}</job-tracker>
         <name-node>${nameNode}</name-node>
   </global>

    <start to="validate" />

    <action name='validate'>
        <java>
            <main-class>com.hadooparchitecturebook.DataValidationRunner
            </main-class>

            <!-- 중략 -->

            <!-- 결과를 캡쳐합니다. 이부분이 중요합니다. -->
            <capture-output />
        </java>
        <ok to="check_for_validation_errors" />
        <error to="fail" />
    </action>

    <!-- 캡쳐된 결과를 가지고 어떠한 액션을 수행할 것인지 결정합니다. -->
    <decision name='check_for_validation_errors'>
        <switch>
            <case to="validation_failure">
                ${(wf:actionData("validate")["errors"] == "true")}
            </case>
            <default to="process_data" />
        </switch>
    </decision>

    <action name='process_data'>
        <java>
            <main-class>com.hadooparchitecturebook.ProcessDataRunner</main-class>
        </java>
        <ok to="end" />
        <error to="fail" />
    </action>

    <action name="validation_failure">
        <java>
            <main-class>com.hadooparchitecturebook.MoveOutputToErrorsAction
            </main-class>
        </java>
        <ok to="end" />
        <error to="fail" />
    </action>

    <kill name="fail">
        <message>Java failed, error message[${wf:errorMessage
                 (wf:lastErrorNode())}]</message>
    </kill>

    <end name="end" />
</workflow-app>

여기서 액션을 수행한 후에 <capture-output />을 사용하여 옵션을 캡쳐한 뒤, 이를 다음 decision node에서 캡쳐된 값을 사용하여 어떠한 액션을 수행할 것인지 결정합니다.

Expression Language Function

캡쳐된 아웃풋의 경우 ${(wf:actionData("validate")["errors"] == "true")} 형태로 데이터를 꺼내서 확인할 수 있습니다. 이러한 형태의 문법을 우지에서는 EL function이라고 합니다. 이러한 EL function을 통해서 다양한 연산들을 지원하고 있습니다. 자세한 내용은 우지 문서 중에 WorkflowFunctionalSpec을 참고하시기 바랍니다.
capture-output의 경우 java, ssh, shell action에서 지원합니다. capture-output은 자바의 프로퍼티 파일 포맷이어야 합니다. 위의 워크플로우 액션 중 validate 액션에서 캡쳐할 아웃풋을 어떻게 기록하는 방법에 대해 알아보겠습니다.

File file = new File(System.getProperty("oozie.action.output.properties"));
Properties props = new Properties();
props.setProperty("errors", "false");

OutputStream os = new FileOutputStream(file);
props.store(os, "");
os.close();  

위의 자바 예제가 캡쳐할 아웃풋을 저장하는 방법입니다. oozie.action.output.properties 파일에 새로운 properties를 작성하는 것이죠. 그러면 우지에서 해당 프로퍼티를 캡쳐하여 아웃풋으로 가지고 있는 것입니다. 그리고 캡쳐된 아웃풋은 wf:actionData("_action_name")["key"]를 통해 decision node에서 참조하게 되는 것입니다.

지금까지 총 3편의 포스트를 통해 Oozie에서 많이 사용하는 워크플로우 패턴에 대해 알아보았습니다. 하둡 에코시스템을 이용한 개발을 하고 있는데 액션들 간에 디펜던시 관리가 필요로 하다면 Oozie가 하나의 선택지가 될 것입니다.

Reference



comments powered by Disqus