Oracle APEX 23.1より、新たなプロセス・タイプとして実行チェーン(Execution Chain)が追加されました。
実行チェーンに含まれるプロセスは、バックグランドで実行できます。
実行チェーンの動作を確認するためのアプリケーションを作りました。
https://github.com/ujnak/apexapps/blob/master/exports/test-execution-chains.zip
表ABP_TRANSACTIONSとプロシージャEXECUTION_CHAIN_STEPのDDLを含んでいます。
実行チェーンMulti Stepsの設定
実行チェーンとしてMulti Stepsを作成しています。設定のバックグラウンドで実行はオンにします。
設定の実行IDをアイテムに返すにP1_ID1、一時ファイル処理にCopy、一時ファイル・アイテムとしてP1_FILEを指定しています。
実行チェーンの開始時に実行ID(Execution ID)がページ・アイテムP1_ID1に設定されます。実行IDは実行チェーンの進捗を確認するビューAPEX_APPL_PAGE_BG_PROC_STATUSの列EXECUTION_IDの値になります。
また、実行IDは実行チェーンを中断する際にも使用します。
ボタンAbortのクリックで実行されるプロセスに、実行チェーンを中断する処理を実装しています。
実行チェーンを中断するために、パッケージAPEX_BACKGROUND_PROCESSに含まれるプロシージャABORTを呼び出します。引数p_process_idを削除し、代わりにp_execution_idを作成します。
パラメータp_application_idは、デフォルトで実行中のアプリケーションIDになります。p_execution_idは実行IDです。引数p_process_idを指定した場合は、同じ実行チェーンから開始したすべての実行が中断します。
ページ・アイテムP1_ID1に設定される実行IDは、実行チェーンが開始したあとに設定されるため、実行チェーンに含まれるプロセスからは参照できません。実行IDを取得するには、プロセス内でAPEX_BACKGROUND_PROCESS.GET_CURRENT_EXECUTIONを呼び出します。
一時ファイル処理としてCopy、および一時ファイル・アイテムとしてP1_FILEを指定しています。一時ファイル処理にはIgnore、Move、Copyのどれかを指定します。
画面にはタイプがファイル参照...のページ・アイテムP1_FILEを作成しています。設定の記憶域タイプとしてTable APEX_APPLICATION_TEMP_FILESを選んでいます。
ページ・アイテムP1_FILEでファイルを選択し、ページの送信を行うと選択されたファイルは表APEX_APPLICATION_TEMP_FILESに保存されます。APEXのプロセスではP1_FILEの値より、アップロードされた内容にアクセスできます。
select filename into l_filename from apex_application_temp_files where name = :P1_FILE;
APEX_APPLICATION_TEMP_FILESにアップロードされたファイルは、同一のセッション内でのみ参照できます。実行チェーンによる処理は、フォアグラウンドのセッションをクローンしたセッションで実行されます(セッションのクローンの説明はこちら)。セッションが異なるため、実行チェーンに含まれるプロセスからはAPEX_APPLICATION_TEMP_FILESに含まれる一時ファイルにアクセスできません。
一時ファイル処理がIgnoreの場合は、実行チェーン以下のプロセスからAPEX_APPLICATION_TEMP_FILESのコンテンツにはアクセスできません。Moveの場合は、一時ファイルがフォアグラウンドのセッションからバックグラウンドのセッションに移動します。実行チェーン以下のプロセスからAPEX_APPLICATION_TEMP_FILESに含まれる一時ファイルにアクセスできるようになりますが、フォアグラウンドのセッションからはアクセスできなくなります。Copyの場合は、一時ファイルがフォアグラウンドのセッションからバックグラウンドのセッションにコピーされます。バックグラウンドとフォアグラウンドのセッションの両方から、一時ファイルにアクセスできます。
つまり、アップロードしたファイルを表にロードする処理を(ブラウザがタイムアウトしないように)バックグラウンドで実行する場合は、一時ファイル処理としてCopyかMoveを指定する必要があります。
実行チェーンでの一時ファイルの扱いには不具合があります(BUG#35335923として登録済み)。
一時ファイル処理をCopyとした場合、ORA-06533:サブスクリプトがカウントを超えています。が発生します。また、Moveの場合はエラーは発生しませんが、一時ファイルが移動しません。
この現象を回避するために、実行チェーンの呼び出し前にcommitを実行します。
実行チェーンMulti Steps以下のプロセスとして、StartedとEndを作成しています。このプロセスでは、パッケージAPEX_BACKGROUND_PROCESSに含まれるプロシージャSET_STATUSを呼び出しています。
引数p_messageに渡した文字列が、ビューAPEX_APPL_PAGE_BG_PROC_STATUSの列STATUS_MESSAGEに設定されます。実行チェーンが終了すると、列STATUS_MESSAGEは空白に戻るようです。また、例外が発生したときのエラー・メッセージも列STATUS_MESSAGEに書き込まれます。
実際の処理をシミュレートするプロセスとしてStep1、Step2、Step3を作成しています。プロシージャEXECUTE_CHAIN_STEPを呼び出しています。
Step1ではp_startに1、p_endに20を指定し、20秒待機します。Step2ではp_startに21、p_endに40を指定し20秒待機、Step3ではp_startに41、p_endに60を指定し20秒待機します。プロシージャEXECUTE_CHAIN_STEPの内部でAPEX_BACKGOUND_PROCESS.SET_PROGRESSを呼び出し、引数p_sofarに経過した秒数、p_totalworkに60を設定しています。この値はビューAPEX_APPL_PAGE_BG_PROC_STATUSの列SOFARおよび列TOTALWORKから参照できます。
引数p_file_itemにはP1_FILEを指定します。無指定の場合は、フォアグラウンドのセッションに紐づくAPEX_APPLICATION_TEMP_FILES内のすべての一時ファイルが対象になります。
実行チェーンSerializedの設定
実行チェーンSerializedでは、設定の実行のシリアライズをオンにしています。また、一時ファイル処理にMoveを設定しています。
実行チェーンSerialized以下に作成したプロセスTest Serializedは、プロシージャEXECUTE_CHAIN_STEPを引数p_startに1、p_endに60を指定して呼び出し、60秒待機します。
実行チェーンLimitedの設定
実行チェーンLimitedでは、設定の実行限度を2にしています。また、一時ファイル処理にIgnoreを設定しています。
実行限度を超えて実行チェーンを呼び出すとバックグラウンド実行制限を超えました。というエラーが発生します。
バッグラウンド処理の上限
実行チェーンMulti Stepsを続けて複数回実行しました。apex.oracle.comでは、ステータスがEXECUTINGになるのはひとつの要求のみで、それ以外はENQUEUEDになります。
実行チェーンのバックグラウンド処理の同時実行可能な上限は、ワークスペース単位およびアプリケーション単位で設定されます。apex.oracle.comではワークスペース単位の上限が1となっており、一度にひとつの実行チェーンのみ実行(ステータスとしてはEXECUTING)され、それ以外は実行中のバックグラウンド処理の終了を待機(同ENQUEUED)します。ワークスペース単位の設定はインスタンス管理者が行なうため、apex.oracle.comでは変更できません。
アプリケーション単位の上限は、アプリケーション定義のプロパティに最大バックグラウンド・ページ・プロセス・ジョブとして設定します。
最大バックグラウンド・ページ・プロセス・ジョブに0を指定すると、実行チェーンのバックグラウンド実行は行われず、開始した実行チェーンはすべて待機(ENQUEUED)します。
Oracle APEX 23.1から提供されているプロシージャAPEX_APPLICATION_ADMIN.SET_MAX_SCHEDULER_JOBSを呼び出すことにより、バックグラウンド実行の上限を変更することができます。
これにより、フォアグラウンドのプロセスが少ない夜間などはバックグランド処理の上限を上げるといった、動的な調整も可能になるでしょう。
EXECUTINGの実行チェーンの処理が終了し実行可能なスロットに空きができると、待機している処理が順次実行されます。
これは、実行チェーンが異なる場合でも同様です。実行チェーンMulti Steps、Serialized、Limitedを続けて実行すると、最初の実行チェーン(この場合はMulti Steps)がEXECUTINGになり、その他はENQUEUEDになります。
特定のユーザーによるリソースの過剰消費を防ぐ、という意味で、安全な実装になっていると言えます。
apex.oracle.comではワークスペース単位のバックグランド処理の上限が1であるため、どのような場合でもバックグラウンド処理はシリアライズされます。そのため、実行チェーンの設定の実行のシリアライズはオンでもオフでも動作は同じです。バックグラウンド処理の上限値が1より大きい値で実行のシリアライズがオンの場合は、すでに実行チェーンがバックグランドで処理中であれば、新たに開始が要求されたバックグランド処理は待機します。
バックグラウンド処理のトランザクション
実行チェーンMulti Stepsには3つのプロセスStep1、Step2、Step3が含まれていて、それぞれが順番に呼び出されるようになっています。
実行チェーンMulti Stepsのバックグラウンド処理が正常に終了すると、以下の3行が表ABP_TRANSACTIONSに書き込まれます。
Step3の処理中(列Sofarの値が40から60の間)にAbortをクリックして、バックグラウンド処理を中断します。列Sofarの値はアボートされた時点の値を維持します。(以下の例では47)。
明示的にcommitを実行していない限り、実行チェーンとして定義されたバックグランド処理がひとつのトランザクションになります。処理を中断する(例外の発生なども同様)とすべてのステップがロールバックされます。
ネストした実行チェーン
以下のような実行チェーンを作成します。
- 実行チェーンTop Chainを作成し、バックグランド実行します。
- Top Chainで最初に実行されるプロセスとしてFirst Stepを作成します。プロセスはつねに実行チェーンのコンテキストで実行されます。
- Top Chainの下に実行チェーンSub Chain1を作成します。これもバックグラウンド実行します。
- Sub Chain1の下にプロセスStep1.1、Step1.2を作成します。
- Top Chainの下に実行チェーンSub Chain2を作成します。これはフォアグラウンドで実行します。
- Sub Chain2の下にプロセスStep2.1を作成します。
実行チェーンTop Chainの実行は以下になります。
Top Chainを実行すると、実行ID(Execution ID)が割り当たります。Process IDは実行チェーンTop ChainのプロセスIDです。すぐに最初のプロセスFirst Stepが実行されます。
Sub Chain1には新たに実行ID(Execution ID)が割り当たります。またProcess IDは実行チェーンSub Chain1のプロセスIDになります。
Top Chainの処理は実行チェーンSub Chain2へ移ります。Sub Chain2はフォアグラウンドで処理されるため実行チェーンTop Chainのコンテキスト(同じ実行ID)で実行されます。実際はSub Chain2に含まれるプロセスStep2.1が実行されていますが、この情報はビューAPEX_APPL_PAGE_BG_PROC_STATUSには表示されていません。
APEX_BACKGROUND_PROCESS.SET_STATUSを呼び出し、実行中のプロセスの情報を更新するという方法もあるとは思いますが、ビューAPEX_APPL_PAGE_BG_PROC_STATUSには、バックグラウンド処理されている実行チェーンの直下に作成されたプロセスまたは実行チェーンまでしか列CURRENT_PROCESS_NAMEとして表示されないようです。
従って、実行チェーンにフォアグラウンドの実行チェーンを含めると、ビューAPEX_APPL_PAGE_BG_PROC_STATUSより進捗を確認するのが難しくなります。そのような設定は避けた方が良いでしょう。
最終的にバックグランド処理された実行チェーンTop Chainと、その中からバックグランド処理された実行チェーンSub Chain1のステータスがSUCCESSとなります。
Oracle APEX 23.1の新機能である実行チェーンによるバックグラウンド処理について、確認した内容は以上になります。
Oracle APEXのアプリケーション作成の参考になれば幸いです。
今までOracle APEXでバックグラウンド処理を行なうには、DBMS_SCHEDULERを使う必要がありました。APEXの実行チェーンはDBMS_SCHEDULERを使ったコーディングより、はるかに容易に利用できます。そもそもコーディングが不要です。DBMS_SCHEDULERを使わないといけないケースはほぼ無くなったでしょう。
完