この章では、Oracle Enterprise Schedulerサブリクエストを使用し、特に、並列リクエスト数が変動する動的コンテキストにおいてデータを並行して処理する方法について説明します。
この章では、次の項目について説明します。
Oracle Enterprise Schedulerサブリクエストは、データを並行して処理する場合に役立ちます。実行中のジョブから発行されるリクエストをサブリクエストと呼びます。単一の親リクエストから複数のサブリクエストを発行できます。Oracle Enterprise Schedulerにおける通常の方法でのパラレル実行はジョブ・セット概念によるものですが、パラレル処理の数が一定にならない場合があります。たとえば、100万行ごとに1つのリクエストを割り当て、先週は、累積された処理対象が970万行となったとします。この場合は、10個のリクエストを割り当てます。460万行が累積された週では5個となります。
Oracle Enterprise Schedulerでは、指定した実行中のリクエスト(ジョブ・リクエスト)によりサブリクエストを発行し、このようなリクエストの完了を待機してから続行できるよう、サブリクエスト機能がサポートされています。
Oracle Enterprise Schedulerでは、オーバーロードされたサブリクエストのメソッドsubmitRequest()
を公開することによって、サブリクエストがサポートされています。ジョブ・リクエストを発行するアプリケーションでは、このAPIを起動してサブリクエストを発行できます。
サブリクエストには、次の制限事項が適用されます。
サブリクエストは1回かぎりの実行としてのみ発行できます。スケジュールは指定できません。通常、サブリクエストは即時実行リクエストとして処理されます。
非定型サブリクエストはサポートされていません。サブリクエストは、アプリケーション内の既存のJobDefinition
オブジェクトに対して発行される必要があります。
ジョブ・セットはサブリクエストに対してサポートされていません。サブリクエストはJobDefinition
オブジェクトに対してのみ発行できます。ただし、実行中の任意のジョブ(ジョブ・セットに含まれる場合があります)によって、サブリクエストを発行できます。
これらの制限によってサブリクエストの実行が簡略化され、発行元のリクエスト自体を実行する場合の混乱や遅延が回避されます。
Oracle Enterprise Schedulerには様々な親リクエストが存在しますが、この章の説明においては、親リクエストはサブリクエストを発行するリクエストのことを指します。
サブリクエストは、標準的な1回かぎりのリクエストの通常フローに従います。ただし、サブリクエストの処理は、親リクエストがその実行を一時停止した場合にのみ開始されます。これを示すために、Oracle Enterprise Schedulerでは、PAUSED
状態が使用されます。この状態は、親リクエストが一時停止され、サブリクエストの終了を待機していることを意味します。
親リクエストによりサブリクエストが発行されると、この親リクエストはそのジョブ・タイプに適切な方法でコントロールをOracle Enterprise Schedulerに戻す必要があり、この状態は親リクエストが実行を一時停止したことを示します。次に、Oracle Enterprise Schedulerにより親の状態がPAUSED
に設定され、サブリクエストの処理が開始されます。サブリクエストが終了すると、親リクエストは、適切なリクエスト・プロセッサによって取得されるまで、PAUSED
のままで準備完了キューに置かれます。その後、この親はRUNNING
状態に設定され、再開されたリクエストとして再実行されます。
例15-1は、5個のサブリクエストを発行するサンプルのPL/SQLジョブです。サブリクエストは1個ずつ発行されます。サブリクエストが発行されるたびに、子リクエストの完了を待機する間にリソースを消費しないよう、親は終了して一時停止状態になります。子が完了すると、親は再起動されます。
例15-1 PL/SQLプロシージャのサブリクエスト
procedure fusion_plsql_subreq_sample( errbuf out NOCOPY varchar2, retcode out NOCOPY varchar2, no_requests in varchar2 default '5', ) is req_cnt number := 0; sub_reqid number; submitted_requests varchar2(100); request_prop_table_t jobProp; begin -- Write log file content using FND_FILE API FND_FILE.PUT_LINE(FND_FILE.LOG, "About to run the sample program with sub-request functionality"); -- Requesting the PAUSED_STATE property set by job identifies request as -- having started for the first time or restarting after being paused. if ( ess_runtime.get_reqprop_varchar(fnd_job.job_request_id, 'PAUSED_STATE') ) is null ) -- first time start then -- Implement the business logic of the job here. FND_FILE.PUT_LINE(FND_FILE.OUT, " About to submit sub-requests : " || no_requests); -- Loop through all the sub-requests. for req_cnt 1..no_requests loop -- Retrieve the request handle and submit the subrequest. sub_reqid := ess_runtime.submit_subrequest(request_handle => fnd_job.request_handle, definition_name => 'sampleJob', definition_package => 'samplePkg', props => jobProp); submitted_requests := sub_reqid || ','; end loop; -- Pause the parent request. ess_runtime.update_reqprop_varchar(fnd_job.request_id, 'STATE', ess_job.PAUSED_STATE); -- Update the parent request with the state of the sub-request, enabling -- the job to retrieve the status during restart. ess_runtime.update_reqprop_int(fnd_job.request_id, 'PAUSED_STATE', submitted_requests); else -- Restart the request, retrieve job completion status and return the -- status to Oracle Enterprise Scheduler. errbuf := fnd_message.get("FND", "COMPLETED NORMAL"); retcode := 0; end if; end;
サブリクエストは、submitRequest
APIをコールすることにより発行できます。サブリクエストはWAIT
状態に設定されますが、親リクエストが実行中の間は、Oracle Enterprise Schedulerによりこのリクエストが処理されることはありません。親リクエストが一時停止された場合にのみ、サブリクエストを処理できます。
サブリクエストを取り消す方法は主に2つあり、ユーザーがサブリクエストを直接取り消すか、または親リクエストを取り消すことによって結果的に取り消します。いずれの方法の場合でも、サブリクエストの取消しプロセスは、他の実行可能なリクエストと同じ方法で処理されます。異なる点は、保留中のサブリクエストがすべて完了して終了状態に到達したときに、親リクエストがOracle Enterprise Schedulerで処理される方法です。
Oracle Enterprise Schedulerにより、WAIT
またはREADY
状態にあるサブリクエストが、直接CANCELLED
に設定されます。サブリクエストが現在実行中である場合、そのサブリクエストはCANCELLING
に設定され、次に、Oracle Enterprise Schedulerにより、そのジョブ・タイプに適切な方法で、実行中の実行可能ファイルの取消しが試行されます。通常、サブリクエストはCANCELLED
状態で終了しますが、そのサブリクエストがライフ・サイクルのどのステージに位置するかによって、他の終了状態で終了する場合があります。親リクエストは、すべてのサブリクエストが終了状態に到達するまで、PAUSED
またはCANCELLING
状態のままとなります。
ユーザーがサブリクエストを取り消すと、前述のように、Oracle Enterprise Schedulerによりそのサブリクエストが取り消されます。親リクエストは、すべてのサブリクエストが完了し、その時点でOracle Enterprise Schedulerにより親リクエストが再開または再起動されるまで、PAUSED
状態のままとなります。これにより、親リクエストはサブリクエストの完了を、取り消されたものとするなどして、適切な方法で処理できます。したがって、サブリクエストの取消しが上位に伝播されることはありません。
ユーザーが親リクエストを取り消すと、Oracle Enterprise Schedulerによって親リクエストがCANCELLING
状態に設定され、次に、前述の方法で、すべての保留中のサブリクエストに対する取消しが開始されます。すべてのサブリクエストが完了すると、親リクエストは、Oracle Enterprise SchedulerによりCANCELLED
に設定され、再開されません。親リクエストの取消しは、そのサブリクエストに伝播されます。
サブリクエストのライフ・サイクルは通常のリクエストのライフ・サイクルと同じであり、WAIT
またはREADY
状態である場合、保留にできます。親リクエストは、サブリクエストが保留になっている間、PAUSED
状態のままとなります。
サブリクエストについての削除操作は、サブリクエストに関する情報が失われてデータが不明瞭となるため、許可されません。サブリクエストは、その親リクエストがパージされると自動的にパージされます。
Oracle Enterprise Schedulerを使用すると、リクエストにより複数のサブリクエストを発行できます。実行中のリクエストにより複数のサブリクエストが発行される場合があります。これらすべてのサブリクエストは、親リクエストが一時停止してPAUSED
状態になると、Oracle Enterprise Schedulerによって処理されます。
このような複数のサブリクエストの場合、親リクエストは、すべてのサブリクエストが終了した場合にのみ再開されます。
また、サブリクエストは、任意の深さまで発行することもできます。これにより、ネストされたサブリクエストが作成されます。したがって、このようなサブリクエストの発行の深さについて制限はありません。これは、スタックのプッシュ操作とポップ操作に似ています。
Java実行可能ファイルにより、RuntimeService.submitRequest
を使用してサブリクエストを発行できます。サブリクエストが発行された後、親リクエストは、サブリクエストを処理できるようにするために一時停止することを、Oracle Enterprise Schedulerに示す必要があります。これは、親がExecutionPausedExcpetion
をスローしてリクエストがPAUSED
状態に遷移することによって行われます。サブリクエストが完了すると、親リクエストは再開されたリクエストとして再度実行されます。RequestExecutionContext
を使用すると、実行可能ファイルが再開されたリクエストとして実行中かどうかを判別できます。
ジョブ実行がサブリクエストの発行後に一時停止すると、実装において実行スレッドを一時停止するという概念がないため、Oracle Enterprise Schedulerでは、その実行があらゆる意味で完了したとみなされます。したがって、このような一時停止されたジョブを再開するには、Oracle Enterprise Schedulerによってジョブを再起動する必要があります。このような場合、実行が一時停止された時点から動作を続行することが必要であるのに対し、ジョブ実行は最初から再起動されます。これにより、ジョブ実行において、一時停止された時点を表すなんらかの実行状態を格納することが必要となります。再開したとき、ジョブはこのような状態を取得して一時停止された時点に移動し、ここから続行できます。
通常、ビジネス・ロジック全体における一時停止されたそれぞれの時点から、確定的な方法でジョブを再開できるようにするための実行状態は、個々のジョブで定義する必要があります(ジョブが一時停止された時点は複数存在する可能性があります)。これには、ステップ番号を格納して、再開時にその特定のステップに移動するという簡単な場合と、一時停止時にビジネス・ロジックにとって重要な状態を大規模なデータ・セットに格納する場合があります。Oracle Enterprise Schedulerでは、状態全体を格納するための完全なソリューションまたはフレームワークは提供できません。
Oracle Enterprise Schedulerでは、ジョブがその一時停止された時点を文字列の形式で格納するための簡易的な方法を提供しており、この文字列は、親ジョブがその実行を一時停止するときに指定できます。親ジョブが再開するとき、親では、必要に応じて使用するために、一時停止状態の値を取得できます。
Javaジョブにより、一時停止状態文字列を特別なExecutionPausedException
コンストラクタを使用して指定できます。状態パラメータは、親リクエストがPAUSED
状態に設定されたときにOracle Enterprise Schedulerによって保存された一時停止状態文字列を表します。
public ExecutionPausedException(String message, String state)
再開された親は、親実行可能ファイルに渡されたRequestExecutionContext
に対してgetPausedState()
をコールすることにより、一時停止状態の値を取得できます。
単一の文字列値では不十分な場合は、親ジョブにより、setRequestParameter()
を使用して任意の数のプロパティをOracle Enterprise Schedulerに書き込むことができ、再開時にはgetRequestParameter()
を使用してこれらのプロパティを取得できます。
サブリクエストが発行されると、Oracle Enterprise Schedulerによりリクエストの状態がWAIT
に設定されますが、遅延モードでは、親リクエストが一時停止するまでディスパッチされません。
Javaジョブの親リクエストは、ExecutionPausedException
をスローすることによって、サブリクエストを処理する準備が整ったことを示します。Oracle Enterprise Schedulerでは、このような例外を受信すると、親リクエストの状態をPAUSED
に設定し、親が一時停止したという内容のシステム・イベント・メッセージを発行した後、その親に対する待機中のすべてのサブリクエストを準備完了キューにディスパッチします。
サブリクエストは、Oracle Enterprise Scheduler内の通常のライフ・サイクルに従って実行されます。指定された親リクエストのすべてのサブリクエストが終了すると、親リクエストを再開できます。
親の再開する準備が整うと、Oracle Enterprise Schedulerによって、親リクエストは準備完了キューに置かれます。親の状態は、取得を待機している間はPAUSED
のままとなります。Oracle Enterprise Schedulerにより親リクエストが準備完了キューから取得されると、リクエストの状態はRUNNING
に設定され、リクエストの実行可能ファイルは再開されたリクエストとしてコールされます。
サブリクエストが発行されることなくリクエストが一時停止された場合は、すべてのサブリクエストが終了したものとして処理されます。つまり、これはPAUSED
状態で準備完了キューに置かれ、再開されたリクエストとして処理するために取得されます。
サブリクエストの最終状態は、その親実行可能ファイルが完了したときにOracle Enterprise Schedulerが親リクエストを処理する方法、および親リクエストの最終状態には影響を及ぼしません。親リクエストが再開すると、親リクエストのジョブ・ロジックはサブリクエストに関する情報を取得できるようになり、このデータを必要に応じて使用して、後続のアクションを決定します。親リクエストの最終状態は、親リクエストが完了した状態(成功、エラー、警告または取消し)のみに基づきます。
Oracle Enterprise Schedulerでは、リクエストごとにRequestType
属性が含まれています。この属性は、リクエストがシングルトン、ジョブ・セットの一部、再帰リクエスト、サブリクエストなどのいずれかであるかを示します。
サブリクエストのRequestType
は、SUB_REQUEST
またはUNVALIDATED_SUB_REQUEST
です。UNVALIDATED_SUB_REQUEST
は、Oracle Enterprise SchedulerのPL/SQLインタフェースを介して発行されたが、まだ検証されていないサブリクエストを表します。親リクエストのRequestType
は、SINGLETON
、RECUR_CHILD
、JOBSET_STEP
またはSUBREQUEST
のいずれかです。その他すべてのリクエスト・タイプは、サブリクエストの親になることができないリクエストを表します。
サブリクエストに対する親リクエストのID属性は、そのサブリクエストを発行したリクエストです。
通常、リクエストがREADY
からRUNNING
状態に遷移する場合、リクエストにより非互換性ロックが取得されます。これらのロックは、リクエストが終了して終了状態(SUCCEEDED
、ERROR
、WARNING
、CANCELLED
など)になるまで解放されません。
サブリクエストの親によって取得された非互換性ロックは、親リクエストがPAUSED
状態の間も引き続き有効です。サブリクエストの親によってブロックされたリクエストはどれも、サブリクエストが実行される間、および親リクエストが再開されて終了するまでブロックされたままとなります。
サブリクエストは非互換性のすべてのルールに従います。したがって、Oracle Enterprise Schedulerでサブリクエストを実行する準備が整っているときに、互換性のない任意のリクエストが現在実行中である場合は、サブリクエストがブロックされることがあります。このような時間ウィンドウでは、親リクエストはPAUSED
状態のままとなり、一方、サブリクエストはBLOCKED
状態に遷移します。
これは、サブリクエストを発行するJavaジョブ・タイプのJavaクラスの例です。プロシージャによって2つのサブリクエストが発行され、それぞれの間に一時停止します。各サブリクエストでは同じJobDefinition
が使用されますが、リクエスト・パラメータSubRequestData
には異なる値が指定されます。親リクエストのoracle.as.scheduler.Executable.execute
メソッドは、指定されたOracle Enterprise Schedulerリクエストに対して合計3回コールされ、それぞれのコールに対する条件とアクションは、次のサマリーに示すように想定されます。
再開されないリクエストとしてメソッドを実行する最初のコールは、次のようになります。
エントリ条件:
RequestExecutionContext.isResumed()
はfalse
となります。
RequestExecutionContext.getPausedState()
はnull
となります。
メソッドのアクション:
リクエスト・パラメータ値MyData1を使用したサブリクエストを発行します。
値がMyPausedState1のpausedState
を使用したExecutionPausedException
をスローします。
Oracle Enterprise Schedulerによって、リクエストがPAUSED
状態に遷移し、サブリクエストが実行され、そのサブリクエストが完了するとリクエストが再開されます。
再開されたリクエストとしてメソッドを実行する最初のコールは、次のようになります。
エントリ条件:
RequestExecutionContext.isResumed()
はtrue
となります。
RequestExecutionContext.getPausedState()
はMyPausedState1となります。
メソッドのアクション:
リクエスト・パラメータ値MyData2を使用したサブリクエストを発行します。
値がMyPausedState2のpausedState
を使用したExecutionPausedException
をスローします。
Oracle Enterprise Schedulerによって、リクエストがPAUSED
状態に遷移し、サブリクエストが実行され、そのサブリクエストが完了するとリクエストが再開されます。
再開されたリクエストとしてメソッドを実行する2回目のコールは、次のようになります。
エントリ条件:
RequestExecutionContext.isResumed()
はtrue
となります。
RequestExecutionContext.getPausedState()
はMyPausedState2となります。
メソッドのアクション:
正常に終了し、例外は発生しません。
Oracle Enterprise Schedulerによって、リクエストがSUCCEEDED
状態に遷移します。
例15-2に、サブリクエストを含むJavaプロシージャを示します。
例15-2 サブリクエストを含むJavaプロシージャ
// constants for the pausedState values private final static String PAUSED_STATE_1 = "MyPausedState1"; private final static String PAUSED_STATE_2 = "MyPausedState2"; public class SubRequestSubmittor implements Executable { // method called by Oracle Enterprise Scheduler when the request is executed public void execute( RequestExecutionContext execCtx, RequestParameters props ) throws ExecutionWarningException, ExecutionErrorException, ExecutionPausedException, ExecutionCancelledException { long requestId = execCtx.getRequestId(); boolean isResumed = execCtx.isResumed(); String pausedState = execCtx.getPausedState(); if (!isResumed) { // Method being called for first time, as non-resumed request. // Submit first subrequest. submitSubRequest(execCtx, "MyData1"); throw new ExecutionPausedException("first subrequest", PAUSED_STATE_1); } else if (PAUSED_STATE_1.equals(pausedState)) { // Method being called for a resumed request. // Submit next subrequest. submitSubRequest(execCtx, "MyData2"); throw new ExecutionPausedException("second subrequest", PAUSED_STATE_2); } else if (PAUSED_STATE_2.equals(pausedState)) { // Method being called for a resumed request. // All done, just return. } else { // Method being called for a resumed request. // Unknown paused state (should never happen). String msg = "Request " + requestId + " was resumed with unexpected pause state " + pausedState; throw new ExecutionErrorException(msg); } } // Submit subrequest with request parameter having the given value. private void submitSubRequest( RequestExecutionContext execCtx, String paramValue ) throws ExecutionErrorException{ RuntimeService rs = null; RuntimeServiceHandle rh = null; try { rs = getRuntimeService(); // Retrieve MetadataObjectId of the subrequest job definition String jobDef = "MySubRequestJobDef"; MetadataObjectId jobDefId = getJobDefinition(jobDef); // Set value for the request parameter used by subrequest. RequestParameters rp = new RequestParameters(); rp.add("SubRequestData", paramValue); // Submit the subrequest rh = rs.open(); long subReqId = rs.submitRequest(rh, execCtx, "subrequest submitter", jobDefId, rp); } catch (Exception e) { String msg = "Error while submitting subrequest for request " + ExecCtx.getRequestId(); throw new ExecutionErrorException(msg, e); } finally { if (null != rh) { try { rs.close(rh); } catch (Exception e) { String msg = "Error while submitting subrequest for request " + ExecCtx.getRequestId(); throw new ExecutionErrorException(msg, e); } } } } // Get RuntimeService. private RuntimeService getRuntime() throws ExecutionErrorException { // implementation not shown } // Retrieve MetadataObjectId for a given job definition name. private MetadataObjectId getJobDefinition( String jobDef ) throws ExecutionErrorException { // implementation not shown } }
ESS_RUNTIME
PL/SQLパッケージは、サブリクエストを発行するために、SQLジョブ・リクエストによって使用されます。これには、リクエストのプロシージャが再開されたリクエストとして実行されているかどうかの判別、および一時停止状態文字列の取得のためのサポートも含まれています。
Javaリクエストの場合、親リクエストがRuntimeService.submitRequest
メソッドを使用してサブリクエストを発行し、その後、サブリクエストを実行できるように親リクエストが一時停止する準備が整うと、ExecutionPausedException
をスローします。
SQLリクエストの場合は、サブリクエストを発行するために、ess_runtime.submit_subrequest
が使用されます。親リクエストは、サブリクエストの実行準備が整ったとき、ess_runtime.mark_paused
をコールし、遷移をコミットして、例外を発生させることなく正常に返す必要があります。mark_paused
メソッドは、親リクエストのプロシージャから正常に返されると、親リクエストをPAUSED
に設定してサブリクエストを実行できるようにする必要があることをOracle Enterprise Schedulerに通知します。mark_paused
メソッドでは、オプションの引数がサポートされており、この引数を使用して、一時停止状態文字列を指定できます。
サブリクエストは、親リクエストが例外を発生させることなくmark_paused
をコールし、コミットして、正常に返されるまで実行されないことに注意してください。例外が発生した場合、Oracle Enterprise Schedulerでは親リクエストをPAUSED
状態に設定せず、かわりに、SQLエラー・コードに応じて親の状態がERROR
またはWARNING
に設定されます。さらに、サブリクエストは自動的にCANCELLED
となり、実行されません。
サブリクエストが終了すると、親リクエストのPL/SQLプロシージャは、Java実行可能ファイルのときと同じように、再開されたリクエストとして再実行されます。
Java実行可能ファイルの場合、RequestExecutionContext
はリクエストが再開中かどうかを示し、親リクエストが一時停止したときにスローされるExecutionPausedException
を介して指定された、一時停止状態文字列も示します。
SQLリクエストの場合、ess_runtime.is_resumed
は、リクエストのプロシージャが再開されたリクエストに対して実行中であるかどうかを示します。メソッドess_runtime.get_paused_state
は、リクエストが一時停止された場合、ess_runtime.mark_paused
プロシージャを介して指定された一時停止状態文字列を返します。
これは、ESS_RUNTIME
パッケージを使用してサブリクエストを発行するSQLジョブ・タイプのPL/SQLストアド・プロシージャの例です。プロシージャによって2つのサブリクエストが発行され、それぞれの間に一時停止します。各サブリクエストでは同じJobDefinition
が使用されますが、リクエスト・パラメータSubRequestData
には異なる値が指定されます。PL/SQLストアド・プロシージャは、指定されたOracle Enterprise Schedulerリクエストに対して合計3回コールされ、それぞれのコールに対する条件とアクションは、次のサマリーに示すように想定されます。
再開されないリクエストとしてのプロシージャへの最初のコールは、次のようになります。
エントリ条件:
ess_runtime.is_resumed
はfalse
となります。
ess_runtime.get_paused_state
はnull
となります。
プロシージャのアクション:
リクエスト・パラメータ値MyData1を使用したサブリクエストを発行します。
一時停止状態を示すMyPausedState1を使用して、一時停止としてマークされます。
正常に終了し、例外は発生しません。
Oracle Enterprise Schedulerによって、リクエストがPAUSED
状態に遷移し、サブリクエストが実行され、そのサブリクエストが完了するとリクエストが再開されます。
再開されたリクエストとしてのプロシージャへの最初のコールは、次のようになります。
エントリ条件:
ess_runtime.is_resumed
はtrue
となります。
ess_runtime.get_paused_state
はMyPausedState1となります。
プロシージャのアクション:
リクエスト・パラメータ値MyData2を使用したサブリクエストを発行します。
一時停止状態を示すMyPausedState2を使用して、一時停止としてマークされます。
正常に終了し、例外は発生しません。
Oracle Enterprise Schedulerによって、リクエストがPAUSED
状態に遷移し、サブリクエストが実行され、そのサブリクエストが完了するとリクエストが再開されます。
再開されたリクエストとしてのプロシージャへの2回目のコールは、次のようになります。
エントリ条件:
ess_runtime.is_resumed
はtrue
となります。
ess_runtime.get_paused_state
はMyPausedState2となります。
プロシージャのアクション:
正常に終了し、例外は発生しません。
Oracle Enterprise Schedulerによって、リクエストがSUCCEEDED
状態に遷移します。
例15-3に、サブリクエストを含むPL/SQLプロシージャを示します。
例15-3 サブリクエストを含むPL/SQLプロシージャ
procedure fusion_plsql_subreq_sample( errbuf out NOCOPY varchar2, retcode out NOCOPY varchar2, no_requests in varchar2 default '5', ) is req_cnt number := 0; sub_reqid number; submitted_requests varchar2(100); request_prop_table_t jobProp; begin -- Write log file content using FND_FILE API FND_FILE.PUT_LINE(FND_FILE.LOG, "About to run the sample program with sub-request functionality"); -- Requesting the PAUSED_STATE property set by job identifies request as -- having started for the first time or restarting after being paused. if ( ess_runtime.get_reqprop_varchar(fnd_job.job_request_id, 'PAUSED_STATE') ) is null ) -- first time start then -- Implement the business logic of the job here. FND_FILE.PUT_LINE(FND_FILE.OUT, " About to submit sub-requests : " || no_requests); -- Loop through all the sub-requests. for req_cnt 1..no_requests loop -- Retrieve the request handle and submit the subrequest. v_idx := v_idx + 1; v_req_props.extend; v_req_props(v_idx).prop_name := 'SubRequestData'; v_req_props(v_idx).prop_datatype := ess_runtime.STRING_DATATYPE; v_req_props(v_idx).prop_value := 'MyData1'; ess_runtime.set_submit_args(v_req_props, 'MyData1', 'MyData12', '1998-11-29') sub_reqid := ess_runtime.submit_subrequest(request_handle => fnd_job.request_handle, definition_name => 'sampleJob', definition_package => 'samplePkg', props => jobProp); submitted_requests := sub_reqid || ','; end loop; -- Pause the parent request. ess_runtime.update_reqprop_varchar(fnd_job.request_id, 'STATE', ess_job.PAUSED_STATE); -- Update the parent request with the state of the sub-request, enabling -- the job to retrieve the status during restart. ess_runtime.update_reqprop_int(fnd_job.request_id, 'PAUSED_STATE', submitted_requests); else -- Restart the request, retrieve job completion status and return the -- status to Oracle Enterprise Scheduler. errbuf := fnd_message.get("FND", "COMPLETED NORMAL"); retcode := 0; end if; end;