2024年1月29日月曜日

APEXワークフローによる並列処理の実装を確認する

Oracle Corporationの公式ブログに、APEX 23.2のAPEXワークフローで並列処理(BPMNにおける並列ゲートウェイ)を実装する方法を紹介している記事が掲載されています。

APEXの開発者であるAnanya Chatterjeeさんによる以下の記事です。

Custom Plugins for non-sequential steps in APEX Workflow
https://blogs.oracle.com/apex/post/custom-plugins-for-non-sequential-steps-in-apex-workflow

新入社員のオンボーディング・プロセスを、APEXワークフローとして実装しています。

英語の元記事では、以下のワークフローを作成しています。


本記事では上記のワークフローから、タイムアウトの処理とメール通知を省略したワークフローを作成して、並列処理の実装を学習します。作成するワークフローは以下です。


これではわからないのでFlows for APEXのフロー・モデラーを使って、BPMNでフローを記述してみました。

赤枠で囲った部分が、APEXワークフローのアクティビティRequest Accessが行っている処理になります。この処理は、Workflow Activityプラグインとして実装されています。

承認タスクEmployee Badge Access(社員バッチの承認)とEmp Laptop Approval(ラップトップの購買承認)のふたつの承認タスクを作成し、両方のタスクが処理されるまで待機します。両方の承認タスクともに承認されたときにアクティビティRequest Accessの結果はtrueとなり、どちらかが却下された時は結果はfalseになります。その後、次のアクティビティ(切替えのAccess Approved)へ進みます。

両方が承認されたときに、アクティビティComplete Trainingに移り、新入社員がトレーニングの終了を確認するとワークフローが完了します。


APEXワークフローの並行処理の部分はアクティビティRequest Accessのコードに実装されています。APEXのダイアグラムには、承認タスクEmployee Badge AccessEmp Laptop Approvalは現れません。

つまり、APEX 23.2のAPEXワークフローではBPMNの並列ゲートウェイにあたる記述ができないため、Workflow Activityプラグインを作成することで並列処理を実装しています。

以下より、元記事の手順に従って新入社員のオンボーディングを処理するAPEXアプリケーションを作成してみます。

クイックSQLの以下のモデルより表EMP_STATSEMP_ONBOARDING_STATUSを作成します。表EMP_ONBOARDING_STATUSに列TRAINING_STATUSONBOARDING_STATUSが含まれていますが、今回の記事ではほぼ使いません(列ONBOARDING_STATUSREQUESTEDを設定するだけ)。

英語の元記事では、これらの列を更新するアクティビティUpdate Onboarding SuccessUpdate Onboarding Failureの追加は読者への課題となっています。

レビューおよび実行をクリックし、表の作成までを実施します。


元記事ではAPEXアプリケーションにPL/SQLコードを埋め込んでいますが、本記事では説明を短縮するため、パッケージEBA_DEMO_WF_PARALLEL_PKGにまとめました。記事の末尾に掲載したスクリプトを実行し、パッケージEBA_DEMO_WF_PARALLEL_PKGを作成します。

スクリプトの実行にはSQLスクリプトを使います。


空のAPEXアプリケーションを作成します。名前新入社員オンボーディングとします。

アプリケーションの作成をクリックします。


共有コンポーネントタスク定義を開きます。


承認タスクとしてEmployee Badge AccessEmp Laptop Approval、アクション・タスクとしてComplete Trainingを作成します。

タスク定義Employee Badge Accessを作成します。タイプ承認タスクです。件名に以下を記述します。静的IDEMPLOYEE_BADGE_ACCESSです。

Approve Badge access for &EMPNO. - &ENAME.

作成をクリックします。


タスク詳細ページは、ページ番号を指定して作成します。

アクション・ソースとしてを選択し、表名EMP_STATS(表)アクション表の主キー列としてEMPNO(Number)を指定します。


参加者に、潜在的所有者としてRALMUELLを追加します。社員バッチによるアクセスを承認できるのは、ユーザーRALMUELLだけです。


パラメータとして、JOINING_DATEMGR_NAMEを追加します。両方ともデータ型文字列です。


アクションとしてOn Badge Access Completedを追加します。


アクションタイプコードを実行イベント時完了を選択します。結果承認済却下済は選択せず、結果にかかわらず承認タスクが完了したときに、このアクションを実行します。

コードに以下を記述します。
eba_demo_wf_parallel_pkg.complete_badge_access(
    p_task_pk => :APEX$TASK_PK
    ,p_task_outcome => :APEX$TASK_OUTCOME
);
プロシージャCOMPLETE_BADGE_ACCESSは、表EMP_ONBOARDING_STATUSの列BADGE_ACCESSを承認タスクの結果(APPROVEDまたはREJECTED)で更新します。その後、列LAPTOP_STATUSを確認し、値がPENDINGでない(APPROVEDまたはREJECTED)であれば、APEX_WORKFLOW.CONTINUE_ACTIVITYを呼び出してAPEXワークフローのアクティビティRequest Accessの次の処理(切替えAccess Approved)に遷移させます。


タスク定義Emp Laptop Approvalを作成します。タイプ承認タスクです。件名に以下を記述します。静的IDEMP_LAPTOP_APPROVALです。

Laptop Request for &ENAME.

作成をクリックします。


タスク詳細ページは、ページ番号3を指定して作成します。

アクション・ソースとしてを選択し、表名EMP_STATS(表)アクション表の主キー列としてEMPNO(Number)を指定します。


参加者に、潜在的所有者としてJANEを追加します。ラップトップの購入を承認できるのは、ユーザーJANEだけです。


アクションとしてOn Laptop Access Completedを追加します。


アクションタイプコードを実行イベント時完了を選択します。結果承認済却下済は選択せず、結果にかかわらず承認タスクが完了したときに、このアクションを実行します。

コードに以下を記述します。
eba_demo_wf_parallel_pkg.complete_laptop_access(
    p_task_pk => :APEX$TASK_PK
    ,p_task_outcome => :APEX$TASK_OUTCOME
);
プロシージャCOMPLETE_LAPTOP_ACCESSは、表EMP_ONBOARDING_STATUSの列LAPTOP_ACCESSを承認タスクの結果(APPROVEDまたはREJECTED)で更新します。その後、列BADGE_STATUSを確認し、値がPENDINGでない(APPROVEDまたはREJECTED)であれば、APEX_WORKFLOW.CONTINUE_ACTIVITYを呼び出してAPEXワークフローのアクティビティRequest Accessの次の処理(切替えAccess Approved)に遷移させます。

プロシージャCOMPLETE_BADGE_ACCESSと対になる処理です。


タスク定義Training Completionを作成します。タイプアクション・タスクです。件名Complete Training Formを記述します。静的IDTRAINING_COMPLETIONです。


タスク詳細ページは、ページ番号8を指定して作成します。

参加者に、潜在的所有者として&ENAME.を追加します。トレーニングの終了の確認は、新入社員それぞれが実施します。

パラメータとしてENAMEを追加します。ラベルEmployee Nameデータ型文字列です。


以上でタスク定義の作成は完了です。

社員バッチの承認ラップトップの承認タスクを内部で作成するプラグインを作成します。

共有コンポーネントプラグインを開きます。


作成済みのプラグインが一覧されます。作成をクリックします。


プラグインの作成最初から行います。へ進みます。


作成するプラグインの名前Onboarding Tasks内部名ONBOARDING_TASKSとします。タイププロセスを選択します。タイプがプロセスのプラグインは、データベース・サーバーで実行されるためPL/SQLで処理を記述します。

コールバック実行ファンクション名として、以下を設定します。このプロシージャ内でAPEX_APPROVAL.CREATE_TASKを呼び出し、社員バッチとラップトップの承認タスクを作成しています。

#OWNER#.eba_demo_wf_parallel_pkg.create_tasks

完了ファンクション名として、以下を設定します。実際にこのプラグインを割り当てたワークフロー・アクティビティの完了は、それぞれの承認タスクアクションに実装されます。このファンクションは、完了が成功したというステータスを返しています。

#OWNER#.eba_demo_wf_parallel_pkg.complete_tasks

Oracle APEXではPL/SQLコードを埋め込むことができるコンポーネントがいくつがありますが、埋め込んだコードの代わりにパッケージに含まれるプロシージャ名やファンクション名を指定することもできます。

サポート対象コンポーネント・タイプワークフロー・アクティビティチェックを入れ、標準属性完了の待機チェックを入れます。

ここで一旦、プラグインの作成を行います。


プラグインが作成されるとカスタム属性を追加できるようになります。

カスタム属性として、REQUESTOREMPNODATE OF JOININGMANAGER NAMEを追加します。


追加する属性のラベルREQUESTOREMPNOといった名前を設定します。設定タイプページ・アイテムを選択します。APEX 23.2ではドロップダウン・リストにページ・アイテムが2行表示されますが、どちらを選んでも大丈夫なようです。軽微な不具合でしょう。EMPNOのみ必須オンにします。


以上でワークフロー・アクティビティに使えるプロセス・プラグインOnboarding Tasksが作成できました。

社員バッチの承認(承認タスクEmployee Badge Access)、ラップトップの購買承認(承認タスクEmp Laptop Approval)、新入社員によるトレーニング終了の確認(アクション・タスクTraining Complete)およびワークフロー・アクティビティのプロセス・プラグインOnboarding Tasksが作成できました。

これらをワークフローを作成します。

共有コンポーネントワークフローを開きます。


作成済みのワークフローが一覧されます。作成をクリックします。


作成するワークフローの識別名前Onboarding Workflowとします。タイトルはOnboarding Workflow for &EMP_NAME.とします。詳細静的IDとしONBOARDING_WFを設定します。


ワークフローの作成手順については、ハンズオン資料「Oracle APEXでワークフローを実装してみよう!」に詳しく紹介しています。ワークフローの作成手順を紹介すると記事が長くなりすぎるため、以下では作成したワークフローについて説明をします。

ワークフロー・バージョンの識別ワークフロー・バージョン1.0とします。設定状態開発中になります。


ワークフローにパラメータを作成します。以下のパラメータを作成します。

静的IDDEPARTMENT(ラベルはDepertment)、DESIGNATION(同Designation)、EMP_EMAIL(同Employee Email)、EMP_NAME(同Employee Name)、JOINING_DATE(同Joining Date)、MGR_EMAIL(同Manager Email)およびREQUESTOR(同Requestor)です。JOINING_DATEを除いて変数データ型VARCHAR2必須オンです。


JOINING_DATE変数データ型TIMESTAMP WITH TIME ZONEアプリケーションの書式マスクセッション・ステート書式マスクとしてYYYY-MM-DD HH24:MIを設定します。この書式マスクは英語の元記事から変更しています。元記事では月にMONを使っていますが、MONを使用すると日本語環境で問題が発生することが多いです。


ワークフロー・バージョン変数としてEmployee IDを作成します。

静的IDEMPLOYEE_IDラベルEmployee ID変数データ型NUMBERです。他に変数としてApproverTaskOutcomeがありますが、これらはワークフローにヒューマン・タスクのアクティビティを含めると自動的に作成されます。


アクティビティCreate Employee Recordの設定です。

英語の元記事ではPL/SQLコードを埋め込んでいますが、PL/SQLコードをパッケージEBA_DEMO_WF_PARALLEL_PKGに含めているため、タイプAPIの呼び出しに置き換えています。

設定パッケージEBA_DEMO_WF_PARALLEL_PKGプロシージャまたはファンクションとしてCREATE_EMPLOYEE_RECORDを指定します。


パラメータファンクションの結果アイテムとして、ワークフロー・バージョン変数EMPLOYEE_IDを指定します。このアクティビティに設定された処理は、新入社員の名前や部署などを表EMP_STATSに登録したときに割り当てられた従業員番号(自動採番される主キー列EMPNOの値)を返しています。ワークフロー・バージョン変数EMPLOYEE_IDに設定された従業員番号は、これ以降のワークフロー・アクティビティから参照されます。


その他の引数には、対応するワークフロー・パラメータを割り当てます。

パラメータp_emp_nameEMP_NAMEp_designationDESIGNATIONp_joining_dateJOINING_DATEp_departmentDEPARTMENTを割り当てます。p_joining_dateを除いて、データ型VARCHAR2です。


パラーメータp_joining_dateデータ型TIMESTAMP WITH TIME ZONE書式マスクYYYY-MM-DD HH24:MIを設定します。


パラメータp_workflow_idは、タイプ静的値を選択し、静的値としてAPEXワークフローの内部変数である&APEX$WORKFLOW_ID.を設定します。データ型NUMBERです。


アクティビティRequest Accessの設定です。

タイプとして、先ほど作成したプラグインOnboarding Tasksを選択します。

設定REQUESTORにはワークフロー・パラメータのREQUESTOREMPNOにはワークフロー・バージョン変数のEMPLOYEE_IDDATE OF JOININGにはワークフロー・パラメータのJOINING_DATEMANAGER NAMEにはMGR_EMAILを指定します。


タイプ切替えのアクティビティAccess Approvedの設定です。

切替えタイプTrue False Checkを選択します。条件条件タイプファンクション本体を選択します。ファンクション本体に以下のPL/SQLコードを記述します。
return eba_demo_wf_parallel_pkg.access_approved(
        p_employee_id => :EMPLOYEE_ID
    );
ファンクションEBA_DEMO_WF_PARALLEL_PKG.ACCESS_APPROVEDは、社員バッチとラップトップの両方が承認されているとtrueを返します。


アクティビティComplete Trainingの設定です。

タイプヒューマン・タスク - 作成を選択します。設定定義アクション・タスクとして作成したタスク定義Training Completionを選択します。ディテール主キー・アイテムとして、ワークフロー・バージョン変数のEMPLOYEE_IDを指定します。

新入社員がアプリケーションにアクセスし、社員バッチとラップトップの両方が承認されていることを確認したら、このワークフローは終了します。


パラメータEmployee Nameには、ワークフロー・パラメータEMP_NAMEを指定します。


アクティビティAccess Approvedfalseのときは、終了状態終了英語はTerminatedなので本当は中断)で終了します。


正常なパスの終了状態完了になります。


アクティビティAccess ApprovedComplete Trainingを繋ぐ接続名前Yes条件タイミングTrueです。


アクティビティAccess Approved中断を繋ぐ接続名前No条件タイミングFalseです。


その他の接続には、特別な設定を行いません。

新入社員オンボーディングのワークフローの設定は以上になります。

最後にAPEXアプリケーションに、ページをいくつか作成します。

最初に新入社員のオンボーディングを開始するページを作成します。

ページの作成を開始します。


空白ページを選択します。


ページ番号、ページの名前Request Onboardingとします。

ページの作成をクリックします。


ページが作成されます。

ワークフローを開始する際に必要なワークフロー・パラメータに与える値を入力するページ・アイテムを作成します。ワークフロー・パラメータREQUESTORを除く、すべてのワークフロー・パラメータについて、対応するページ・アイテムを作成します。

作成するページ・アイテムはP4_NAMEラベルEmployee Name)、P4_EMAIL(同Employee Email)、P4_JOINING_DATE(同Joining Date)、P4_DESIGNATION(同Designation)、P4_DEPARTMENT(同Department)、P4_MANAGER_EMAIL(同Manager Email)です。

ページ・アイテムP4_JOINING_DATEを除いて、タイプテキスト・フィールドです。すべてのページ・アイテムで、セッション・ステートストレージリクエストごと(メモリーのみ)を選択します。


ページ・アイテムP4_JOINING_DATEは、タイプとして日付ピッカーを選択し、外観書式マスクYYYY-MM-DD HH24:MIを指定します。


新入社員のオンボーディングを開始するボタンSTART_ONBOARDINGを作成します。ラベルStart Onboarding動作アクションはデフォルトのページの送信です。


先ほど作成したワークフローOnboarding Workflowを開始するプロセスを作成します。

識別名前Submit Workflowタイプとしてワークフローを選択します。

設定タイプ開始を選択し、定義Onboarding Workflowを選びます。サーバー側の条件ボタン押下時START_ONBOARDINGを指定します。


REQUESTORを除くパラメータには、対応するページ・アイテムが作成されています。タイプとしてアイテムを選び、アイテムにそれぞれ対応したページ・アイテムを指定します。


パラメータREQUESTORについては、タイプ静的値を選び、静的値として&APP_USER.を指定します。アプリケーションにサインインしているユーザー、つまりこのワークフローを開始したユーザーがREQUESTORになります。


以上で新入社員のオンボーディングを開始するページは完成です。

サインインしたユーザーに割り当てられているタスクを一覧する、統合タスク・リストのページを作成します。

ページの作成を開始し、統合タスク・リストを選択します。


ページ番号5名前My Tasksとします。自分に割り当てられているタスクを一覧するため、レポート・コンテキストマイ・タスクを選択します。

ページの作成をクリックします。統合タスク・リストのページはカスタマイズせず、作成されたページをそのまま使用します。


続けて、ページの作成を開始し、ワークフロー・コンソールを選択します。


自分自身が開始したワークフローを一覧し、一覧より選択したワークフローの詳細を表示するページを作成します。

レポートのページのページ番号名前Monitor Onboarding Workflowとします。レポート・コンテキスト自分で開始を選択します。選択したワークフローの詳細を表示するフォームのページ番号フォーム・ページ名Onboarding Detailsとします。フォーム・ページ・モードドロワーとします。

ページの作成をクリックします。ワークフロー・コンソールもカスタマイズせずに、そのまま使用します。


最後にタスク定義Training Completion詳細ページをカスタマイズします。今までの手順通りにアプリケーションを作成していると、詳細ページはページ番号8で作成されています。

ページ・デザイナでページ番号タスクの詳細を開きます。

ボタンCOMPLETEラベルを完了からAcknowledgeに変更します。


新たにタイプ静的コンテンツリージョンを作成し、ソースHTMLコードに以下を記述します。

Please click on the Acknowledge button to confirm the completion of your new-hire training


リージョン開発者情報コメント・アウトします。


以上でAPEXアプリケーションが完成しました。

ワークスペースにデモ用のユーザーを追加する代わりに、デモ用の認証スキームを作成します。

認証スキームタイプとしてカスタムを選択し、ソースPL/SQLコードに以下を記述します。

設定認証ファンクション名demo_authenticationを指定します。

認証スキームの作成を実行し、認証スキームを作成します。


作成された認証スキームをカレント・スキームにします


以上で、作成したアプリケーションの動作を確認する準備ができました。

アプリケーションを実行し、ユーザーSTEVEでサインインします。

Request Onboardingを開き、Employee NameJAYを指定してStart Onboardingをクリックします。

新入社員JAYのオンボーディングが開始し、社員バッチの承認タスクがユーザーRALMUELL、ラップトップの承認タスクがJANEに割り当てられます。


ユーザーSTEVEが開始したワークフローを一覧します。

Monitor Onboarding Workflowを開きます。たった今開始したワークフローが、ステータスがアクティブで一覧されます。


ワークフローの詳細を確認すると、アクティビティRequest AccessWaiting(待機中)になっていることが確認できます。


ユーザーRALMUELLでサインインしてMy Tasksを開くと、新入社員JAYの社員バッチの承認タスクが割り当たっています。

承認します。


ユーザーJANEでサインインしてMy Tasksを開くと、新入社員JAYのラップトップの承認タスクが割り当たっています。

これも承認します。


ユーザーSTEVEでサインインし、Monitor Onboarding Workflowからワークフローの詳細を確認します。

アクティビティComplete TrainingWaiting(待機中)になっていることが確認できます。


ユーザーJAYでサインインしMy Tasksを開くと、アクション・タスクComplete Training Formが割り当たっていることが確認できます。


詳細のフォームを開いて、画面右下にあるボタンAcknowledgeをクリックします。新入社員がアクション・タスクを承認すると、このワークフローは完了します。


ユーザーSTEVEでサインインしMonitor Onboarding Workflowより、ワークフローの完了を確認します。


社員バッチまたはラップトップの承認タスクが却下されると、ワークフローはアクティビティAccess Approvedから中断に遷移します。


今回の記事は以上になります。

APEXワークフローがBPMNの並行ゲートウェイと等価な記述をサポートしていないのは大きなディスアドバンテージと言えますが、カスタム・プラグインで実装することにより対処できる場合もあるでしょう。

今回作成したAPEXアプリケーションにエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/new-hire-onboarding.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。