この章では、Javaコードを起動する、長時間実行されるジョブ、またはコンテナ管理でないジョブをサポートするために、Oracle Enterprise Schedulerを使用して非同期Javaジョブを起動する方法について説明します。
この章では、次の項目について説明します。
通常、Oracle Enterprise SchedulerのJavaジョブ・リクエストは、Oracle WebLogic Server内部の専用スレッドで実行されますが、長時間実行されるJavaジョブ・リクエスト、またはコンテナ管理でないJavaジョブ・リクエストを発行する機能が必要となる場合があります。
Oracle Enterprise Schedulerでは、次の特徴を持つ非同期Javaジョブの起動がサポートされています。
Oracle Enterprise Schedulerのユーザーの視点から見ると、非同期Javaジョブの起動をスケジュールする場合に差異はありません。
Oracle Enterprise Schedulerの観点からは、非同期Javaジョブの起動ジョブ・リクエストは、発行されるとキューに追加され、実行後はすぐに戻ります(ジョブ・リクエストはRUNNING
状態になります)。Oracle Enterprise Schedulerは、後処理を適用またはジョブを完了できるようになった時点でジョブから応答があるまで、操作を続行します。
非同期Javaジョブによって、Oracle Enterprise Scheduler外部の様々な外部ジョブが開始されます。外部ジョブまたは外部ジョブを管理するエンティティでは、ジョブのステータスをOracle Enterprise Schedulerに通知する必要があります。
Oracle Enterprise Schedulerの非同期Javaジョブは、Oracle Enterprise Schedulerのジョブ・リクエストと外部メカニズムで構成されています。Oracle Enterprise Schedulerのジョブ・リクエストは、標準のOracle Enterprise SchedulerのJavaジョブ・リクエストと同様に実装されますが、標準のOracle Enterprise Schedulerリクエストとは異なり、シナリオによっては非同期Javaジョブ・リクエストによる作業が行われない場合があります。非同期Javaジョブ・リクエストの目的は、外部メカニズムをトリガーすることのみです。外部メカニズムはペイロード(データベースの監視や円周率の計算など、存続期間が長いプロセス)を実行しますが、Oracle Enterprise SchedulerのJavaジョブを実行するスレッドとは分離可能である必要があります。外部メカニズムとしてSOAコンポジット(BPEL)を使用したり、Oracle ADFビジネス・コンポーネントの非同期Webサービス、別のスレッド、JVM、マシンまたは他のメカニズムを使用できます。外部メカニズムとクライアント・アプリケーションの間の通信方法は、ジョブ所有者によって決定されます。ただし、非同期Javaジョブで重要なのは、非同期ジョブを表す物理的なJavaオブジェクトへのポインタが、Oracle Enterprise Schedulerのメモリーに格納されないということです。この理由は次のとおりです。
ジョブが実行される時間が不確定であり、このハンドルをキャッシュすると、リソースが無駄に消費されるため。
存続期間が長いジョブは、コンテナの再起動後まで継続可能である必要があるため。このオブジェクトはキャッシュされず、ガベージ・コレクションされる可能性が高いため、ジョブはステートレスである必要があり、ジョブ・リクエストとそれらを実行している外部メカニズムとの間の相関は、その発行元アプリケーションが保持する必要があります。Oracle Enterprise Schedulerでは、この理由に対するジョブ・リクエストIDとジョブ・リクエスト・ハンドルが提供されています。この情報は、再起動後まで継続可能にするために、維持する必要があります。
非同期Javaジョブのexecute()
メソッドの役割は、実際の作業が実行される外部メカニズムを設定することです。このメソッドは、外部メカニズムを開始した後、戻ります。非同期Javaジョブの起動execute()
メソッドでは、実際の作業は実行できません。executeメソッドの実行中に例外がスローされ、ジョブの初期化中に問題が発生して実行に失敗したことがOracle Enterprise Schedulerに通知される場合があります。executeメソッドの実行中の例外によって、Oracle Enterprise Schedulerに対して、外部メカニズムで実行中の実際の作業に問題が発生したと通知されることはありません。Oracle Enterprise Schedulerでは、例外が捕捉された場合は後続の処理を行わないため、開始または使用された可能性のあるリソースが解放されていることを、ジョブ所有者が確認する必要があります。例外がスローされない場合、Oracle Enterprise Schedulerによってジョブが実行状態になり、ガベージ・コレクションできるように、ジョブのオブジェクトのハンドルが解放されます。
非同期Javaジョブにより、WebサービスAddressingヘッダーを設定して、リモート・ジョブの作業を簡略化できます。
相関
WSA messageID
ヘッダーを使用して、レスポンス・メッセージをリクエストに関連付けます。Oracle Enterprise Schedulerでは、メソッドRequestExecutionContext.getIdString
が提供されており、このメソッドにより、WSA messageID
ヘッダーの値に使用されるIDが返されます。
返信Addressing
WSA ReplyTo
およびFaultTo
ヘッダーは、Oracle Enterprise Schedulerの汎用コールバック・サービスへの直接返信に使用できます。現在、Oracle Enterprise Schedulerでは、これらのアドレスの取得はサポートされていません。
Oracle Enterprise Schedulerでは、非同期コールバックのWebサービス操作setAsyncRequestStatus
が提供されています(例16-15のインタフェースを参照)。これには、ステータスやステータス・メッセージなどの入力情報、および明示的に指定する相関情報が必要です。
Oracle Enterprise Schedulerでは、別のメカニズム、つまり、非同期コールバックのための汎用のJava Required Files Webサービス・プロバイダが提供されています。このWebサービス・プロバイダではあらゆるタイプのペイロードが受け入れられ、メッセージはSOAPMessage
オブジェクトとして配信されます。メッセージをリクエストに関連付けるために、WSA relatesTo
ヘッダーが抽出されます。このヘッダーに、元のリクエストのWSA messageID
ヘッダーが移入されます。Action
ヘッダーは、レスポンスが非同期ジョブの完了とフォルトのいずれに起因するかを決定するのに使用します。レスポンスがフォルトに起因する場合、非同期ジョブのリクエスト・ステータスは、一時的にERROR
に設定されます。レスポンスが非同期ジョブの正常完了に起因する場合、非同期ジョブのリクエスト・ステータスは、一時的にSUCCESS
に設定されます。SOAPMessage
本文が抽出され、Updatable.onEvent
メソッドに渡される文字列に変換されます。
Webサービス・プロバイダのアドレスは、http://<
host
>:<
port
>/ess-async/essasynccallback
です。
Oracle Enterprise Schedulerでは、インタフェースoracle.as.scheduler.Updatable
が提供されており、このメソッドを使用すると、アプリケーション・コードで開始された更新イベントをジョブ・リクエストで受信できます。ジョブ・リクエストが更新されると、Oracle Enterprise Schedulerにより、クライアント・クラスにUpdatable
インタフェースを実装するかどうかが決定されます。クライアント・クラスにUpdatable
インタフェースを実装する場合、ホスティング・アプリケーションのMDBのコンテキストでジョブ・クラスの新規オブジェクトがインスタンス化され、onEvent
メソッドがコールされます。このメソッドでは、Webサービスの起動により決定されたリクエスト・ステータス、およびジョブに認識されるフォーマットで情報を表した文字列(Oracle Enterprise Scheduler WebサービスからのSOAPMessage
本文など)を使用します。このメソッドでは、情報のログへの記録などの処理が実行される場合があります。その後、ステータスおよびステータス・メッセージを含むUpdateAction
オブジェクトが返されます。
リクエストの実行に関連するユーザーのコンテキストで、onEvent
に対するコールが発生します。
ジョブにUpdatable
インタフェースが実装されていない場合、イベントはonEvent
に渡されたステータス(Oracle Enterprise Schedulerへの非同期コールバックから決定されるステータスなど)に基づいて処理されます。
Updatableインタフェースの詳細は、例16-12を参照してください。
非同期ジョブの完了時にOracle Enterprise Schedulerに通知するには、次の2通りの方法があります。
Webサービス・インタフェースの使用
EJBインタフェースの使用
Oracle Enterprise SchedulerのWebサービス操作setAsyncRequestStatus
を起動すると、これにより、非同期リクエストのステータスおよび関連情報が設定されます。この操作に関連して、次の情報が必要となります。
setAsyncRequestStatus(String requestExecutionContext, AsyncStatus status, String statusMessage)
ここで
requestExecutionContext
は、開始イベントの一部として渡す必要がある文字列です。このパラメータは、Oracle Enterprise SchedulerジョブのRequestExecutionContext
オブジェクトから導出されます。
status
はSUCCESS
、ERROR
、WARNING
、PAUSE
、CANCEL
、BIZ_ERROR
またはUPDATE
のいずれかです。
statusMessage
は次のとおりです。
ステータスがERROR
またはBIZ_ERROR
の場合は、エラー・メッセージとなります。
ステータスがWARNING
の場合は、警告メッセージとなります。
ステータスがPAUSED
の場合は、一時停止状態となります。
ステータスがUPDATE
の場合は、定義してジョブにより適宜解析したカスタマイズ済文字列となります。
ステータスがSUCCESS
またはCANCEL
の場合、値は無視されます。
WebアプリケーションにおけるWebサービスの実装の詳細は、『Oracle Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド』の「WebサービスのFusion Webアプリケーションへの統合」および『Oracle Fusion Middleware Webサービスのためのセキュリティおよび管理者ガイド』の「WebLogic Webサービスの保護と管理」を参照してください。
非同期Javaジョブのexecute()
メソッドが正常に起動され、ジョブ・リクエストが外部メカニズムで実行されている場合、Oracle Enterprise Schedulerでは、他のジョブの処理が続行されます。ジョブ・リクエストが完了するか、またはエラーが発生した場合、そのジョブの発行元アプリケーションに通知を返す必要があります。この通信チャネルは、エージェントおよびクライアント・アプリケーション所有者に依存します。その後、発行元アプリケーションによって、ジョブのステータスがOracle Enterprise SchedulerにローカルEJBを介して通知されます。このEJBにもリモート・インタフェースがある場合、かわりに、外部メカニズムによりリモートEJB自体が起動されることもあります。EJBによって、ジョブ・ステータスが設定され、適切な後処理が行われます。すべてのEJB参照をカプセル化するヘルパー・クラスが提供されています。このヘルパーは依存関係インジェクションを使用するため、コンテナ内部で使用されている場合にのみ動作します。ヘルパー・クラスには成功、エラー、警告および取消しを通知するためのメソッドが含まれています。
ジョブを取消し可能にする場合は、AsyncCancellable
インタフェースを実装する必要もあります。このインタフェースは、その取消しメソッドにより、当該ジョブに対してRequestExecutionContext
とRequestParameters
も提供される点で、通常の取消し可能なインタフェースとは異なります。指定されたコンテキストおよびパラメータを使用して、ペイロードを実行中の外部メカニズムを判別し、停止するよう要求する必要があります。(ジョブのAsyncCancellable.cancel()
の実装ではなく)外部メカニズムにより、Oracle Enterprise Schedulerにジョブが取り消されたことが通知されます。
注意: 現在、実行中のOracle ADFビジネス・コンポーネントの非同期Webサービス・プロセスを終了する方法はありません。 |
非同期リクエストを使用して、BPELプロセスをOracle Enterprise Schedulerから起動できます。Oracle Enterprise Schedulerの非同期Javaジョブを使用して、BPELプロセスを起動します。BPELプロセスが完了すると(成功したか、エラーや警告が発生したか、または取り消されたかどうかに関係なく)、BPELプロセスにより、Oracle Enterprise SchedulerのWebサービス操作を使用してOracle Enterprise Schedulerに通知されます。
BPELプロセスを起動するこの方法の手順は、次のとおりです。
Oracle Enterprise Schedulerの非同期Javaジョブを作成します。
BPELプロセスをOracle Enterprise SchedulerのJavaジョブから起動します。
BPELプロセスが完了したら、Oracle Enterprise Scheduler Webサービスに完了ステータスでコールバックします。Webサービス操作のメソッドを使用して、Oracle Enterprise Schedulerにリクエストの完了を通知します。詳細は、第16.2.6.1項「非同期ジョブ完了時のWebサービスを使用した通知」を参照してください。
Oracle Enterprise Schedulerでは、完了情報が受信されると、リクエストについて必要な後処理(必要に応じて)を完了します。
関連するWebサービスを直接起動したり、例16-1に示すように、BPELプロセスを起動することをイベント・メディエータに指示するイベントを公開できます。
例16-1 イベント・メディエータを介してBPELプロセスを起動するジョブ
import oracle.as.scheduler.RequestParameters; import oracle.as.scheduler.ExecutionCancelledException; import oracle.as.scheduler.ExecutionErrorException; import oracle.as.scheduler.ExecutionPausedException; import oracle.as.scheduler.ExecutionWarningException; import oracle.as.scheduler.RequestExecutionContext; import javax.xml.namespace.QName; import oracle.fabric.blocks.event.BusinessEventConnection; import oracle.fabric.blocks.event.BusinessEventConnectionFactory; import oracle.fabric.common.BusinessEvent; import oracle.integration.platform.blocks.event.BusinessEventBuilder; import oracle.integration.platform.blocks.event.BusinessEventConnectionFactorySupport; import oracle.xml.parser.v2.XMLDocument; import org.w3c.dom.Element; // Async imports import oracle.as.scheduler.AsyncExecutable; import oracle.as.scheduler.AsyncCancellable; public class BPELJob implements AsyncExecutable, AsyncCancellable { public BPELJob() { } public void execute(RequestExecutionContext ctx, RequestParameters params) throws ExecutionErrorException, ExecutionWarningException, ExecutionCancelledException, ExecutionPausedException { // Publish an event to the Event Mediator publishEvent(ctx.getRequestId() + "", ctx.toString(), "ESS_EVENT"); } // Cancel public void cancel (RequestExecutionContext ctx, RequestParameters requestParams) { publishEvent(ctx.getRequestId() + "", ctx.toString(), "CANCEL_ESS_EVENT"); return; } // cancel // Event publishing private final String eventName = "ESSDemoEvent"; private final String eventElement = "ESSDemoEventElement"; private final String eventNamespace = "http://xmlns.oracle.com/apps/ta/essdemo/events/edl"; private final String schemaNamespace = "http://xmlns.oracle.com/apps/ta/essdemo/events/schema"; private XMLDocument buildEventPayload(String correlationId, String key, String eventType) { Element masterElem, childElem1, childElem2, childElem3; XMLDocument document = new XMLDocument(); masterElem = document.createElementNS(schemaNamespace, eventElement); document.appendChild(masterElem); childElem1 = document.createElementNS(schemaNamespace, "requestId"); childElem1.appendChild(document.createTextNode(correlationId)); masterElem.appendChild(childElem1); childElem2 = document.createElementNS(schemaNamespace, "executionContext"); childElem2.appendChild(document.createTextNode(key)); masterElem.appendChild(childElem2); childElem3 = document.createElementNS(schemaNamespace, "eventType"); childElem3.appendChild(document.createTextNode(eventType)); masterElem.appendChild(childElem3); return document; } private void publishEvent(String correlationId, String key, String eventType) { try { // Get event connection BusinessEventConnectionFactory cf = BusinessEventConnectionFactorySupport. findRelevantBusinessEventConnectionFactory(true); if (cf != null) { BusinessEventConnection conn = cf.createBusinessEventConnection(); // Build event BusinessEventBuilder builder = BusinessEventBuilder.newInstance(); // Specify the event name and namespace. In this prototype, // they are constants, eventNamespace, eventName builder.setEventName(new QName(eventNamespace, eventName)); // Specify the event payload. In this prototype, the // getXMLPayload custom method constructs the payload builder.setBody(buildEventPayload(correlationId, key, eventType).getDocumentElement()); BusinessEvent event = builder.createEvent(); // Publish event conn.publishEvent(event, 5); // For debug only System.out.println("Event was sent sucessfully"); } else { // For debug only System.out.println("cf is null"); } } catch (Exception exp) { // For debug only System.out.println("Failed sending event: " + exp.getMessage()); exp.printStackTrace(); } } // publishEvent }
非同期Javaジョブを使用して、BPELプロセスを実行できます。プロセスはイベントによって起動され、そのプロセスを起動したイベント・メディエータによって処理されます。たとえば、図16-1を参照してください。
プロセスの実際の作業は、DoMyWorkモジュールで行われます。
作業が正常に完了すると、AssignAsyncSuccess/AsyncCallbackSUCCESSに制御が移行し、ステータスとしてSUCCESS
が指定され、ステータス・メッセージが指定されずに、Oracle Enterprise SchedulerのWebサービス・コールバックが起動されます。
Oracle Enterprise Schedulerのリクエストが取り消されると、Oracle Enterprise Schedulerジョブの取消しメソッドがコールされます。次に、ジョブ・オブジェクトにより、それを取り消す必要があることがリモート・ジョブに通知されます。取消しが成功すると、リモート・ジョブにより、コールバック・メカニズムを使用してOracle Enterprise Schedulerに通知され、ステータスがCANCELに設定されます。この場合、制御は右端にあるブランチに移行します。
フォルトが発生した場合、制御は中間ブランチに移行します。AsyncCallbackERRORにより、ステータスERROR
およびフォルトからのエラー・メッセージを指定するOracle Enterprise SchedulerのWebサービス・コールバックが起動されます。AsyncCallbackCANCELにより、ステータスCANCEL
を指定する(ステータス・メッセージは指定されません)Oracle Enterprise SchedulerのWebサービス・コールバックが起動されます。
BPELプロセスでは、AssignAsyncError
割当てアクティビティについての図16-2、図16-3および図16-4に示すように、Oracle Enterprise Schedulerの非同期コールバックに対するWebサービス操作の値が必要です。
非同期ジョブとしてのBPELプロセスの実装のユースケースは、次のとおりです。
ヒューマン・ワークフロー通知およびその他のSOA固有アクティビティを使用してタスクの承認を得ます。
ジョブが完了したことをOracle Enterprise Schedulerに通知すると同時に、他のジョブを実行したりセット内の次のジョブに進むことができます。
デザイン・パターンのサマリー
Oracle Enterprise Schedulerの非同期ジョブはAsyncExecutable
インタフェースを実装するJavaジョブであり、このインタフェースは、Oracle Enterprise Schedulerでexecute()
メソッドを実装することによって起動されます。このメソッドを使用すると、execute()
メソッドが完了する、長時間実行されるタスクやリモートのタスク(ビジネス・イベントの呼出しなど)を開始でき、その間、ジョブはOracle Enterprise SchedulerによってRUNNING
ステータスに維持されます。リモート・タスクが完了すると、次のいずれかを実装することにより、ステータス・メッセージを使用してOracle Enterprise Schedulerにその完了が通知されます。
RuntimeService
EJB
Oracle Enterprise SchedulerのWebサービスsetAsyncRequestStatus
操作
このパターンでは、起動されるリモート・タスクが、非同期ジョブのexecute()
メソッドでビジネス・イベントを呼び出すことによってトリガーされるBPELプロセスであることを前提としています。完了、エラーまたは取消しを経たプロセスの終了時に、BPELプロセスによってOracle Enterprise Scheduler Webサービスが起動され、ステータスが適宜設定されます。
関連コンポーネント
図16-5に、Oracle Enterprise Scheduler、SOAメディエータおよびBPELを示します。
ユースケースによっては、Oracle Enterprise SchedulerジョブによってBPELプロセスを双方向方式で起動して、他のジョブに進む前にこのBPELプロセスの完了を追跡する必要があります。Oracle Fusion ApplicationsでJavaコード(Oracle Enterprise SchedulerまたはOracle ADFビジネス・コンポーネント)から非同期Webサービスを起動することは禁止されているため、Oracle Enterprise Schedulerジョブによって非同期BPELプロセスを直接起動することはできず、非同期ジョブの実装タイプに依存する必要があります。
このアプローチはOracle Fusion Middlewareの既存の機能(イベントやBPELなど)を利用するため、お薦めします。
Oracle Enterprise Schedulerの非同期ジョブ機能のかわりに次のアプローチが考えられますが、許可されていません。
JAX-WSプロキシを介したOracle ADFビジネス・コンポーネントやBPELなどの非同期Webサービスの起動: スレッドのブロックおよびコールバック・サービスがOracle Enterprise Schedulerで許可されていません。
BPELをトリガーするビジネス・イベントの呼出し: BPELでOracle ADFビジネス・コンポーネント・サービスを起動し、そのADFビジネス・コンポーネント・サービスでRuntimeService EJBを起動してステータスを設定しますが、複雑でエラーが発生しやすい手順です。
ある経費システムでは経費をインポートして処理するためのOracle Enterprise Schedulerジョブが定期的に実行され、この処理では、通知と承認にヒューマン・ワークフローを活用するために、BPELプロセスの発行が必要となります。このユースケースでは、Oracle Enterprise Schedulerジョブで経費と明細をインポートし、経費ごとに非同期BPEL機能をトリガーするサブリクエストを経費単位で発行します。このサブリクエストはOracle Enterprise Schedulerの非同期ジョブとして実装され、このジョブでは、ビジネス・イベントを呼び出してそのJava execute()メソッドを完了し、BPELの起動時には実行状態を継続してヒューマン・タスク通知を発行し、ユーザー操作の結果を待機します。この結果が取得されると、BPELによって、この特定のサブリクエストが完了したことを通知するOracle Enterprise Scheduler Webサービスが起動されます。
BPELでOracle Enterprise Schedulerの非同期ジョブを実装するには、次の手順を実行する必要があります。
execute()
とcancel()
の各メソッドを記述して、AsyncExecutable
とAsyncCancellable
の各インタフェースを実装するOracle Enterprise SchedulerのJavaジョブを作成します。
Oracle Enterprise Schedulerの非同期ジョブ定義を作成します。
イベント・ペイロード・スキーマ(XSD)およびイベント定義(EDL)の各ファイルを設計します。
Oracle Enterprise Schedulerの非同期ジョブのexecute()および(必要に応じて)取消しメソッドから、ビジネス・イベントをプログラムによって呼び出します。
メディエータおよびBPELを使用してSOAコンポジットを設計します。
エラーに対してフォルト処理と相関onMessage
ブランチを追加し、ジョブ・ステータス更新を取り消します。
Oracle Enterprise Schedulerアプリケーションでは、アプリケーション・コアおよびEnterprise Scheduler ServiceのOracle JDeveloperライブラリを追加し、Oracle Enterprise SchedulerのAsyncExecutable
とAsyncCancellable
の両方のインタフェースを実装する、(標準に従って)適切なクラス・ネーミングとディレクトリ構造を使用して新規Javaクラスを作成するようにしてください。これらのインタフェースを両方ともインポートするには、例16-2に示すように、Oracle Enterprise Schedulerジョブの必要な動作を開始するためにOracle Enterprise SchedulerのRuntimeService
Beanによって起動されるexecute()
とcancel()
の各メソッドを実装する必要があります。
例16-2 Oracle JDeveloperライブラリの追加
public class ASMEventAsyncJob implements AsyncExecutable, AsyncCancellable { public ASMEventAsyncJob() { super(); } public void execute(RequestExecutionContext ctx, RequestParameters params) throws ExecutionErrorException, ExecutionWarningException, ExecutionCancelledException, ExecutionPausedException { publishEvent(ctx.getRequestId() + "", ctx.toString(), "ESS_EVENT"); return; } public void cancel (RequestExecutionContext ctx, RequestParameters requestParams) { publishEvent(ctx.getRequestId() + "", ctx.toString(), "CANCEL_ESS_EVENT"); return; } // cancel
Oracle Enterprise SchedulerのJDeveloperワークスペースで、「新規」をクリックし、Enterprise Scheduler Serviceのテクノロジ・グループを選択して「ジョブ定義」を選択します。図16-6に示すように、Oracle Enterprise Schedulerのジョブ定義の名前を入力して、指定されたJavaJobTypeを選択し、ステップ1で作成したクラスをこのジョブ定義に対してオーバーライドするJavaクラスとして選択します。
ここで、図16-7に示すように、このジョブ定義に対してオーバーライドするJavaクラスとして、ステップ1で開発したクラスを選択し、ユースケースの必要に応じてパラメータおよびアクセス制御を定義します。
SOAコンポジット・デザイナには、ビジネス・イベントのペイロード定義(EDL)の設計に役立つUI機能がありますが、スキーマ(.xsd)を最初に設計する必要があります。例16-3に、サンプルのXSDファイルを示します。
例16-3 サンプルXSDファイル
<?xml version="1.0" encoding="UTF-8" ?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://xmlns.oracle.com/apps/ta/essdemo/events/schema" targetNamespace="http://xmlns.oracle.com/apps/ta/essdemo/events/schema" attributeFormDefault="unqualified" elementFormDefault="qualified"> <xsd:element name="ESSDemoEventElement" type="ESSDemoEventElementType"/> <xsd:complexType name="ESSDemoEventElementType"> <xsd:sequence> <xsd:element name="requestId" type="xsd:string"/> <xsd:element name="executionContext" type="xsd:string"/> <xsd:element name="eventType" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:schema>
ペイロードの要素タイプを完了したら、EDLを手動で作成するか、またはイベント定義ビルダーを使用できます。ビルダーを使用するには、SOAコンポジット・エディタを開き、図16-8に示すように、UIの上部にある稲妻アイコンをクリックして「イベント定義の作成」ウィンドウを開きます。
次に、名前およびネームスペースを割り当てて「追加」をクリックし、図16-9に示すように、この定義に新規イベントを追加します。
「OK」をクリックします。イベント定義サマリーに完成したイベント定義が表示されます。図16-10に示すように、要件の必要に応じて、さらにイベントを追加します。
例16-4に、作成されたEDLファイルのサンプルを示します。
例16-4 EDLファイル
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <definitions xmlns="http://schemas.oracle.com/events/edl" targetNamespace="http://xmlns.oracle.com/ AsyncEssDemoComposite/EventDefinition1"> <schema-import namespace="http://xmlns.oracle.com/singleString" location="xsd/singleString.xsd"/> <schema-import namespace="http://xmlns.oracle.com/apps/ta /essdemo/events/schema" location="xsd/ESSDemoEventSchema.xsd"/> <event-definition name="ESSEvent"> <content xmlns:ns1="http://xmlns.oracle.com/apps/ta/essdemo/events/schema" element="ns1:ESSDemoEventElement"/> </event-definition> </definitions>
Oracle Enterprise Schedulerの非同期ジョブから呼び出されたビジネス・イベントには、いずれのジョブが完了したか、取り消されたか、またはエラーが発生したかをBPELで示すために、リクエストの実行コンテキストのtoString()
値が含まれている必要があります。Javaからのビジネス・イベントのプログラムによる呼出しについては、ビジネス・イベントを呼び出すJavaコードを記述する方法の仕様を含む、ADFからのSOAの起動に関する項で説明しています。呼び出されたこのビジネス・イベントをサブスクライブするSOAコンポジットを宣言して作成するには、イベント・スキーマ(.xsd)および定義(EDL)を設計する必要があります。Javaコードにより、このXML文書を最初から作成する必要があり、QName値(ペイロード構造における要素やネームスペースの属性など)と完全に一致する必要があります。
execute()
メソッドは、Oracle Enterprise Schedulerによりジョブの実行が開始されるときに起動されますが、エンド・ユーザーまたは外部エンティティからOracle Enterprise Schedulerに実行中のジョブを取り消すよう指示があった場合は、Oracle Enterprise SchedulerによってジョブのステータスがCANCELLINGに設定され、cancel()メソッドが起動されます。両方のメソッドで、類似するペイロード・タイプやネームスペースを含むイベントが呼び出されるようにすることをお薦めします。これにより、相関セットを使用して進行中のBPELプロセスに取消しイベントを送信できるようにし、そのBPELプロセスで代替機能を実行してOracle Enterprise Scheduler Webサービスを起動し、ジョブ・ステータスをCANCELLEDに設定できるようにします。
このサンプルでは、イベント呼出しコードがOracle Enterprise Schedulerジョブのクラス・コードに配置されていますが、最適なアプローチはOracle ADFライブラリとしてコードを共有することであり、このプロジェクトにそのライブライをインポートして公開コードの重複を減らすことができます。
(BPEL相関セットで進行中の取消しが許可されるように) requestID
および実行コンテキストのtoString()
値を渡すイベント呼出しコードをコールするサンプル・コードを次に示します。
publishEvent(ctx.getRequestId() + "", ctx.toString(), "ESS_EVENT");
例16-5に、サンプルのイベント呼出しコードを示します。
例16-5 イベント呼出しコード
private final String eventElement = "ESSDemoEventElement"; private final String eventNamespace = "http://xmlns.oracle.com/apps/ta/essdemo/events/edl"; private final String schemaNamespace = "http://xmlns.oracle.com/apps/ta/essdemo/events/schema"; private XMLDocument buildEventPayload(String correlationId, String key, String eventType) { Element masterElem, childElem1, childElem2, childElem3; XMLDocument document = new XMLDocument(); masterElem = document.createElementNS(schemaNamespace, eventElement); document.appendChild(masterElem); childElem1 = document.createElementNS(schemaNamespace, "requestId"); childElem1.appendChild(document.createTextNode(correlationId)); masterElem.appendChild(childElem1); childElem2 = document.createElementNS(schemaNamespace, "executionContext"); childElem2.appendChild(document.createTextNode(key)); masterElem.appendChild(childElem2); childElem3 = document.createElementNS(schemaNamespace, "eventType"); childElem3.appendChild(document.createTextNode(eventType)); masterElem.appendChild(childElem3); return document; } public void publishEvent(String correlationId, String key, String eventType) { // Determine whether we are outside of a JTA transaction try { // Get event connection BusinessEventConnectionFactory cf = BusinessEventConnectionFactorySupport.findRelevantBusinessEventConnectionFactory (true); if (cf != null) { BusinessEventConnection conn = cf.createBusinessEventConnection(); // Build event BusinessEventBuilder builder = BusinessEventBuilder.newInstance(); // Specify the event name and namespace. In this prototype, // they are constants, eventNamespace, eventName builder.setEventName(new QName(eventNamespace, eventName)); // Specify the event payload. In this prototype, the // getXMLPayload custom method constructs the payload builder.setBody(buildEventPayload(correlationId, key, eventType).getDocumentElement()); BusinessEvent event = builder.createEvent(); // Publish event conn.publishEvent(event, 5); // For debug only System.out.println("Event was sent sucessfully"); conn.close(); } else { // For debug only System.out.println("cf is null"); } } catch (Exception exp) { // For debug only System.out.println("Failed sending event: " + exp.getMessage()); exp.printStackTrace(); } } // publishEvent }
このユースケースはBPEL機能によって異なるため、イベント・サブスクリプション用のメディエータを含むSOAコンポジットを作成する必要があり、これにより、ペイロードを変換してBPELプロセスを起動できます。
SOAワークスペースで、新規SOAコンポジットを作成します。このパターンに対してコンポジットを設定するには、Oracle Enterprise Schedulerで呼び出されたイベントをサブスクライブするメディエータを追加して、BPELプロセスに接続します。Oracle Enterprise Scheduler WebサービスWSDLにサービス参照を追加します。次に例を示します。
http://myhost.com:7001/ess/esswebservice?WSDL
1つ以上のネストされたスコープを使用して、BPELプロセスで必要な機能を引き続き作成します。機能は少なくとも1つのプライマリ・スコープ内に存在する必要があり、図16-11に示すように、このスコープでonMessage
イベント(進行中の取消しメッセージの受信用)およびフォルト・ハンドラ・ブランチを追加できます。
Oracle Enterprise Scheduler Webサービスの起動の詳細は、第11章「Oracle Enterprise Scheduler Webサービスの使用」を参照してください。
Oracle Enterprise Schedulerでは、execute()
メソッドのJavaコードが完了した後、Oracle Enterprise Schedulerの非同期ジョブのハートビート監視は一切行われません。ジョブは発行されると、リモート・ジョブ・コード、BPELまたはエンド・ユーザーがOracle Enterprise Schedulerを直接操作してそのジョブのステータスを設定するまで、RUNNING
状態でOracle Enterprise Schedulerインフラストラクチャ内に存在します。このため、BPELプロセスの設計では、Oracle Enterprise Schedulerジョブの存続期間中に最もよく発生する、少なくとも2つのタイプのシナリオを処理するように、また、監視UIにジョブの適切な状態を反映してエンド・ユーザーに示すために、できるかぎり状態情報をOracle Enterprise Schedulerに送信して戻すようにする必要があります。
BPEL処理の取消し:
たとえば、監視UIをエンド・ユーザーが操作してジョブの取消しをリクエストする場合、図16-12に示すように、Oracle Enterprise Schedulerでは、ジョブのステータスがCANCELLING
に更新され、リモート機能が整理されるのを待機して、ジョブが取り消されたことを確認します。
BPEL処理エラー
また、リモート機能で障害が発生した場合、この障害については、リモート機能(この場合にはBPEL)からOracle Enterprise Schedulerに通知する必要があり、このとき、Oracle Enterprise Schedulerに対して、ジョブのステータスがERROR
であることを通知し、実行されたすべてのロギングとステータス・メッセージを提供することが必要になります。これを図16-13に示します。
取消しを確認して適切なステータスをOracle Enterprise Schedulerインフラストラクチャに調整して戻すために、受信する取消しメッセージの受入れや障害のトラップをサポートし、いずれの場合でもOracle Enterprise Schedulerサブシステムを更新できるよう、特定のレイアウト内でBPELを設計する必要があります。このためには、BPELプロセスに、この非同期ジョブの機能を含む少なくとも1つのスコープが存在する必要があります。これにより、取消しやエラーの状態の処理は十分に制御され、その後、これらの状態はOracle Enterprise Schedulerランタイムにおけるジョブのステータスを更新するためにOracle Enterprise Scheduler Webサービスに送信される必要があります。
これらの状態をサポートする基本的なプロセス・フローを作成するには、次の手順を順番に完了する必要があります。
相関セットを作成して、受信Receiveアクティビティを模倣するためにフラグを付けます。
サブステップ1で作成した相関セットを使用して、onMessage
ブランチを作成します。
フォルト処理ブランチを作成します。
必要に応じて、onMessage
ブランチとフォルト処理ブランチにクリーン・アップ・アクティビティを移入し、Oracle Enterprise Scheduler Webサービスを適切なステータスで起動します。
BPELプロセスで他のアクティビティを実行中か、または非同期コールバックを待機中に取消しイベントの受信をサポートするには、プロセスが相関セットを使用して構成されている必要があります。相関セットは、BPELエンジンに対してBPELプロセスを一意に識別するために使用される1つ以上の受信ペイロード属性から作成されるキー値であり、これにより、新規プロセスを開始するかわりに、一致する属性のセットを含む追加サービス・リクエストを現在実行中のプロセスにルーティングできます。相関は非同期リクエスト・レスポンスに使用される標準機能ですが、スコープ・レベルのonMessage
ブランチによって、BPELプロセスでの実行フローを変更するためにも使用できます。
相関セットを設定するには、デザイナでBPELプロセスを開き、Receiveアクティビティをダブルクリックして、「相関」タブをクリックします。
相関セットには、この相関セットのライフ・サイクルの開始点となるアクティビティを示す開始プロパティが含まれていることに注意してください。この場合、BPELプロセスは相関セットのライフ・サイクルが開始する必要がある時点に開始され、これにより、相関イベントはプロセスのどの時点であってもこのプロセスにルーティングされます。
相関セットを作成する手順は、次のとおりです。
任意のReceive、InvokeまたはonMessage
アクティビティの「相関」タブで「新規」アイコンをクリックし、相関セットの名前を指定します。
次に、「追加」をクリックして、相関キーとして使用する1つ以上のプロパティ属性を定義します。
変数属性を設定プロパティとして選択して、「OK」をクリックします。
ステップ2と3を必要に応じて繰り返し、常に一意となる属性セットを作成します。
相関セットのライフ・サイクルが開始するアクティビティで、相関の「開始」フラグを「はい」に設定します。
図16-14に、相関セットが定義され、「開始」フラグが「はい」に設定されたプライマリ(最初の) Receiveアクティビティを示します。
図16-15に、単一のプロパティが定義されたCorrelationSet_1定義を示します(一意キーが作成されていることを確認するには、必要に応じて追加プロパティを定義します)。
相関セットを開始のために定義して設定すると、受信する取消しメッセージを受け入れるために必要なアクティビティを含むonMessage
ブランチをスコープに作成して、補正やクリーンアップを実行し、ジョブの完了ステータスをCANCEL
に割り当てることができるようになります。
注意: この時点で、 |
次の手順を実行して、図16-16に示すように、以前に作成した相関セットをonMessage
ブランチのアクティビティに追加します。
プロセス機能を含むネストされたスコープで、「OnMessageブランチの追加」アイコンをクリックし、スコープの隅に新規フローを作成します。
onMessage
ブランチのアクティビティをダブルクリックしてアクティビティ・エディタを開きます。
「相関」タブを選択します。
「追加」(+)アイコンをクリックして以前に作成した相関セットを選択し、「開始」フラグが「いいえ」に設定されていることを確認して、「OK」をクリックします。
ネストされた作業スコープで様々なアクティビティを実行する過程において、BPELではビジネス・サービスまたはシステム機能からフォルトが発生する場合があります。ほとんどの場合、プロセスのコールにスローして戻すことができる1つ以上のWSDL定義フォルトがビジネス・サービスによって定義されます。通常、BPEL CatchAllフォルト・ブランチでは、発生するすべてのフォルトがそのタイプや原因に関係なくトラップされますが、特定のビジネス・フォルトに対して、異なる動作セットを実行するという要件が製品チームに存在する場合があります。特定のビジネス・フォルトに対して独自の補正動作が実行されるようにする場合、開発者は、WSDL定義済フォルトごとに、指定されたフォルト処理ブランチを作成する必要があります。これらの指定されたフォルト・ハンドラ・ブランチに加えて、スコープから発生するシステム・レベルまたは管理対象外のフォルトをトラップするには、CatchAllフォルト処理ブランチの追加が引き続き必要です。
CatchFaultおよびCatchAllのスコープ・アイコンをクリックして必要なフォルト処理ブランチを作成し、次に、指定されたフォルト処理ブランチをダブルクリックして、これらのブランチが捕捉する指定されたフォルトを定義します。
図16-17に示す使用可能なステータスに注意してください。
必要に応じて、onMessageとフォルト・ブランチにクリーン・アップ・アクティビティを移入し、Oracle Enterprise Scheduler Webサービスを適切なステータスで起動する必要があります。
フォルトが発生したり、onMessageブランチを経由して取消しメッセージを受信した場合は、ジョブのステータスとステータス・メッセージを監視UIに適切に反映するために、Oracle Enterprise Scheduler Webサービスを介して、Oracle Enterprise Schedulerインフラストラクチャを直接更新する必要があります。この結果、各フォルト処理ブランチまたはonMessageブランチは、適切なステータスとステータス・メッセージ値をOracle Enterprise Scheduler Webサービスのinvoke変数に割り当てる必要があり、必要に応じて、invokeアクティビティを含めるか、または意図的に、ジョブ・ステータスの結果に左右されないよう設計された上位順序のスコープに戻り、invokeアクティビティをOracle Enterprise Scheduler Webサービスで実行してから完了します。
また、必要に応じてアクティビティをonMessageおよびフォルト・ブランチにドラッグし、クリーンアップ、記録または補正を行います。
図16-18に、onMessageおよびフォルト処理ブランチを含むスコープの例を示します。
正常に機能するかどうかテストするには、次の一連の手順を実行する必要があります。
次のサイトにナビゲートしてEDN-DB-LOGページを表示し、ログは有効であると表示されていることを確認します。そうでない場合、「有効化」のリンクをクリックします。
http://host:port/soa-infra/events/edn-db-log
独自のアプリケーション(ジョブ・リクエストを発行するためのFusion Middleware Controlのタスク・フロー・ユーザー・インタフェース)を使用してジョブを発行し、ジョブのステータスがRUNNING
であることを確認します。
イベントが即座にEDN-DB-LOGページに表示されます。例16-6に示すように、このイベント・ペイロードを確認します。
例16-6 イベント・ペイロード
Example:Enqueing event: http://xmlns.oracle.com/apps/ta/essdemo/events/edl::ESSDemoEvent from J Body: <business-event xmlns:ns="http://xmlns.oracle.com/apps/ta/essdemo/events/edl" xmlns="http://oracle.com/fabric/businessEvent"> <name>ns:ESSDemoEvent</name> <id>df8e34c1-4c65-4379-b9be-2c692670ebbe</id> <content> <ESSDemoEventElement xmlns="http://xmlns.oracle.com/apps/ta/essdemo/events/schema"> <requestId>3</requestId> <executionContext>3, false, null, 6A4A16757764CD60E0402382B7703F44, 12</executionContext> <eventType>ESS_EVENT</eventType> </ESSDemoEventElement> </content> </business-event> Subject name: Enqueing complete Enqueing event: http://xmlns.oracle.com/apps/ta/essdemo/events/edl::ESSDemoEvent from J Body: <business-event xmlns:ns="http://xmlns.oracle.com/apps/ta/essdemo/events/edl" xmlns="http://oracle.com/fabric/businessEvent"> <name>ns:ESSDemoEvent</name> <id>a4104da8-5579-4434-ab8b-d31a226e3b0f</id> <content> <ESSDemoEventElement xmlns="http://xmlns.oracle.com/apps/ta/essdemo/events/schema"> <requestId>4</requestId> <executionContext>4, false, null, 6A4A2BC7E5477C60E0402382B77041C9, 12</executionContext> <eventType>ESS_EVENT</eventType> </ESSDemoEventElement> </content> </business-event>
サブスクライブするメディエータがトリガーされたら、例16-7に示すように、Fusion Middleware Control ($DOMAIN_HOME/as.log)またはsoa-diagnostic logs ($DOMAIN_HOME/servers/<serverName>logs/<serverName>.log)を確認して、イベントの結果としてのメディエータのアクティビティを確認できます。
例16-7 メディエータのアクティビティ
INFO: MediatorServiceEngine received an event = {http://xmlns.oracle.com/apps/ta/ess/demo/events/edl}ESSDemoEvent Apr 17, 2009 1:57:26 PM oracle.tip.mediator.common.persistence.MediatorPersistor persistCallback INFO: No call back info set in incoming message Apr 17, 2009 1:57:26 PM oracle.tip.mediator.common.persistence.MediatorPersistor persistCallback INFO: Message properties : {id=041ecfcf-8b73-4055-b5c0-0b89af04f425, tracking.compositeInstanceId=50003, tracking.ecid=0000I2pqzVCBLA5xrOI7SY19uEYF00004g:47979} Apr 17, 2009 1:57:26 PM oracle.tip.mediator.dispatch.InitialMessageDispatcher dispatch INFO: Executing Routing Service.. Apr 17, 2009 1:57:26 PM oracle.tip.mediator.dispatch.InitialMessageDispatcher processCases INFO: Unfiltered case list size :1 Apr 17, 2009 1:57:26 PM oracle.tip.mediator.monitor.MediatorActivityMonitor createMediatorCaseInstance INFO: Creating case instance with name :ESSDemoProcess.essdemoprocess_client.process Apr 17, 2009 1:57:26 PM oracle.tip.mediator.dispatch.InitialMessageDispatcher processCase INFO: Immediate case {ESSDemoProcess.adedemoprocess_client.process}with case id : {5B52B4A02B9211DEAF64D3EF6E2FB21D}will be executed Apr 17, 2009 1:57:26 PM oracle.tip.mediator.service.filter.FilterFactory createFilterHandler INFO: No Condition defined
Oracle Enterprise Manager Fusion Middleware ControlコンソールでSOAコンポジットのインスタンスを確認して、エラーを確認します。
http://host:port/em
BPELプロセスにエラーがなく、ヒューマン・ワークフロー通知からのレスポンスが予期されている場合、ワークリストにナビゲートして割り当てられた承認者としてログインし、設計の要件ごとに通知を承認するか、または拒否します。
ここから、BPELプロセスを完了してOracle Enterprise Scheduler Webサービスを起動し、ジョブの完了ステータスとステータス・メッセージを設定する必要があります。監視UIの診断ログで、スタック・トレースとログ・メッセージを確認します。
また、Oracle Enterprise SchedulerスキーマのREQUEST_HISTORY
表で、ジョブの状態の詳細を確認できます。
Oracle ADF UI機能(監視や発行のタスク・フローなど)に関する問題をトラブルシューティングするには、サーバーのコンソール・ログ、アプリケーション・ログおよびサーバー診断ログを使用して、失敗の原因と理由を確認します。
イベント機能に関する問題(リクエストの実行コンテキストが失われない状態でイベントがBPELプロセスに到達しないなど)をトラブルシューティングするには、EDNデータベース・ログ・ページ(http://host:post/soa-infra/events/edn-db-log
)を使用してイベント・ペイロードを検査し、スキーマ定義と慎重に比較します(多少不一致があってもトランスフォーメーションは成功する場合がありますが、BPELに対してリクエスト・コンテキスト値が欠落したスケルトン・ペイロードが生成されます)。Oracle JDeveloperおよびサードパーティのツールを使用して、イベント・ペイロードのスキーマを検証したり、そのペイロードに対してトランスフォーメーションをデバッグできます。
メディエータ(BPEL SOA機能)をトラブルシューティングするには、診断にOracle Enterprise Managerおよびサーバー・コンソールまたは診断ログ・ファイルを使用して、ロギングにAppsLoggerセンサー変数を使用します。
実行時のOracle Enterprise Schedulerのトラブルシューティングの詳細は、『Oracle Fusion Middleware Oracle Enterprise Scheduler管理者ガイド』の「Oracle Enterprise Schedulerのトラブルシューティング」を参照してください。
Oracle Enterprise Schedulerの非同期Javaジョブは、リモート・ジョブに依存してOracle Enterprise Schedulerを完了ステータスで更新した後、リクエスト処理を完了できます。リモート通信の性質上、ネットワーク障害などが原因で、リモートのリクエスト・ステータスがOracle Enterprise Schedulerで受信されない場合があります。このような場合、リクエストは非終了状態でスタックされることがあります。
タイムアウト・リクエストの終了状態への遷移は、次のことを可能にするので、重要です:
このジョブ・リクエストで保持されている非互換性ロックを解放します。
ジョブ・リクエストがジョブ・セット・ステップの場合、ジョブ・セットを続行します。
リクエストがサブリクエストの場合、親リクエストを再開します。
ジョブ・リクエストが削除またはパージされるようにします。
Oracle Enterprise Schedulerのシステム・プロパティSystemProperty.ASYNC_REQUEST_TIMEOUT
を使用すると、非同期Javaジョブに対するジョブ・リクエストのタイムアウト値を設定できます。デフォルトでは、このプロパティは有効化されておらず、その値はゼロ以下となっています。
プロパティは、ジョブ定義メタデータで設定されたり、ジョブ・リクエストの発行時に設定される場合があります。値は、ジョブ・リクエストによりローカル実行が開始されたときから、非同期ジョブの最終ステータスがリモート・ジョブから受信されるまでの期間(分単位)を表します。
指定された非同期ジョブ・リクエストの場合、システム・プロパティSystemProperty.ASYNC_REQUEST_TIMEOUT
を0より大きい値に設定します。
指定されたリクエストについて、RequestDetail.isTimedOut
はタイムアウトのステータスを示します。タイムアウトしたリクエストは、例16-8に示す問合せを使用して検出できます。
例16-8 タイムアウト・ステータスの表示
Filter timedOutRunningFilter = new Filter( RuntimeService.QueryField.TIMED_OUT.fieldName(), Filter.Comparator.EQUALS, Boolean.TRUE) .and( RuntimeService.QueryField.STATE.fieldName(), Filter.Comparator.EQUALS, State.RUNNING.value()); runtimeService.queryRequests(handle, timedOutRunningFilter, null, true);
例16-9に示すように、REQUEST_HISTORY_VIEW
を使用して、同様の問合せを実行できます。
タイムアウト値がない場合、リモート・ジョブがステータスをOracle Enterprise Schedulerに配信せずに完了した非同期リクエストは、RuntimeMXBean.completeAsyncRequest
を使用して直接完了することがあります。注意が必要であることを示すフラグをリクエストに付けるためのタイムアウト値がないため、タイムアウトのないリクエストを慎重に追跡する必要があります。
タイムアウトがないジョブ・リクエストの管理の詳細は、『Oracle Fusion Middleware Oracle Enterprise Scheduler管理者ガイド』の「Oracle Enterprise Schedulerのトラブルシューティング」を参照してください。
Oracle Enterprise Schedulerでは、プロパティSystemProperty.ASYNC_REQUEST_TIMEOUT
が設定された非同期ジョブ・リクエストを定期的に確認します。最終ステータスが受信されずに時間が超過すると、タイムアウトしたというフラグがジョブに付けられます。それ以外の場合、ジョブの状態は影響を受けず、RUNNING
状態のままとなります。その一方で、Oracle Enterprise Schedulerでは、リモート・ジョブからのステータス更新を引き続き受け入れます。フラグは、リモート・ジョブのステータス調査が必要である可能性があることを示します。
リモート・ジョブは完了したが、そのステータスがOracle Enterprise Schedulerに配信されなかった場合、リクエストを手動で完了できます。
ジョブが実行中かどうかがわからない場合など、ジョブのステータスを自動で決定できない場合もあります。ジョブが実行中の場合、ジョブ・リクエストが終了状態に遷移しないようにする必要があります。ジョブが終了状態に遷移すると、非互換性ロックが解放され、互換性のないジョブ・リクエストが同時に実行される可能性があります。
次に例を示します。
リモート・サービスが開始したときに非同期Javaジョブでエラーが発生し、リモート・サービスが実際に起動されたことが不明確になります。リモート・ジョブが実行中かどうかが判断されるまで、ジョブ・リクエストがエラー状態にならないようにする必要があります。ジョブが実行中である可能性がある場合、ジョブでは、ジョブ・リクエストがERROR_MANUAL_RECOVERY
状態に遷移する必要があることをOracle Enterprise Schedulerに示すために、oracle.as.scheduler.ExecutionManualRecoveryException
をスローする必要があります。
Oracle Enterprise Schedulerの非同期Javaジョブはjava.lang.Error
をスローしますが、これにより、リモート・サービスが起動されたかどうかをOracle Enterprise Schedulerに示すことはありません。
生成されたジョブはクラスタ化された環境で実行中であり、ジョブ・リクエストはOracle Enterprise Scheduler instance1で実行中です。Oracle Enterprise Scheduler instance1サーバーは、関連するPerlエージェントとともに停止します。instance1がしばらくの間リカバリしない場合、ジョブ・ステータスは不明となります。このタイプの状況では、プロパティState.ERROR_MANUAL_RECOVERY
を使用します。これは、リカバリ操作が手動で起動されるまでジョブ・リクエストの処理を一時停止する非終端状態です。取得された非互換性ロックは、手動リカバリが完了するまで保持されます。
手動リカバリ対象としてマークされた非同期ジョブの処理の詳細は、『Oracle Fusion Middleware Oracle Enterprise Scheduler管理者ガイド』の「Oracle Enterprise Schedulerのトラブルシューティング」の手動リカバリを要するスタック非同期ジョブの処理に関する項を参照してください。
一部のジョブ・リクエストが不完全な状態でスタック状態となった場合、最初に、ジョブ・リクエストが通常の方法で完了できるかどうかを判断する必要があります。たとえば、ジョブ・リクエストがRUNNING
状態の場合、リモートで実行中の非同期Javaジョブのためである場合があります。リモート・ジョブが応答できない場合、ジョブ・リクエストの取消しを試行する必要があります。これにより、ジョブ・リクエストはCANCELLING
状態に遷移します。ジョブ・リクエストがCANCELLED
状態に遷移しない場合は、リカバリ対象の候補にすることができます。
リカバリ対象となるリクエストの子リクエストはすべて、すでに完了している必要があり、これは、そのプロセス・フェーズがProcessPhase.Complete
であることを意味します。RequestDetail.getProcessPhase()
を実行して、プロセス・フェーズを取得できます。
RuntimeService.queryRequests
を使用すると、例16-10に示すフィルタを使用して、不完全な子リクエストを判別する問合せを実行できます。
例16-10 不完全な子リクエストのフィルタリング
Filter filter = new Filter(RuntimeService.QueryField.ABSPARENTID.fieldName(), Filter.Comparator.EQUALS, requestId) .and(RuntimeService.QueryField.REQUESTID.fieldName(), Filter.Comparator.NOT_EQUALS, requestId) .and(RuntimeService.QueryField.PROCESS_PHASE.fieldName(), Filter.Comparator.NOT_EQUALS, ProcessPhase.Complete.value());
いずれかの子リクエストで手動リカバリが必要であると判断された場合、最初に、これらのジョブに対してrecoverRequest
を起動します。不完全な子リクエストを含む親リクエストに対してrecoverRequest
が起動されると、例外がスローされます。この例外メッセージには、不完全な子リクエストがリストされます。例16-11に、recoverRequest
構文を示します。
例16-11 recoverRequest
/** * Attempts to force a request to complete under certain conditions. * <p> * 1. The request must already by in a terminal state, {@code * State.CANCELLING}, or {@code State.ERROR_MANUAL_RECOVER}. * If a request is in another state, * {@code RuntimeService.cancel} must be called first. If the * request does not eventually transition to {@code State.CANCELLED}, * then this operation may be invoked on the request. * 2. All child requests of the given request must already be complete. * <p> * A <b>completed></b> request is a request in a terminal state with * a process phase of {@code ProcessPhase.Complete}. * <p> * Note that this operation will lock the request. * <p> * @param requestId the request identifier of the request. * @throws IOException if a protocol error occurred. * @throws InstanceNotFoundException if the request is not found * @throws OperationException if the given request has child requests * that are not complete. * @throws RuntimeOperationsException if a RuntimeService subsystem failure * occurs. */ public void recoverRequest( long requestId ) throws IOException, InstanceNotFoundException, OperationsException, RuntimeOperationsException;
同期Javaジョブの手動による処理の詳細は、『Oracle Fusion Middleware Oracle Enterprise Scheduler管理者ガイド』の「Oracle Enterprise Schedulerのトラブルシューティング」、手動リカバリを要する同期Javaジョブの処理に関する項を参照してください。
Oracle Enterprise Schedulerの新規非同期コールバック・インタフェースのサンプル・コードを例16-12、例16-13、例16-14および例16-15に示します。
例16-12 Oracle Enterprise SchedulerのUpdatableインタフェース
public interface Updatable { /** * Invoked by Enterprise Scheduler when a job request is updated. * This method must eventually return control to the caller. * * @param context An oracle.as.scheduler.RequestExecutionContext * object for this request. * * @param parameters the request parameters associated with this request * * @param resultCode the {@code * oracle.as.scheduler.async.UpdateAction.ActionCode} indicating the * action that generated this event. * * @param messagePayload a {@code String} representing the body of this * event. The content and format are not known by the Enterprise Scheduler. */ public UpdateAction onEvent( RequestExecutionContext context, RequestParameters parameters, oracle.as.scheduler.async.AsyncStatus resultCode, String messagePayload ); }
UpdateAction
クラスはUpdatable.onEvent
によって返されます。
例16-13 Oracle Enterprise SchedulerのUpdateActionクラス
package oracle.as.scheduler.async; /** * Enumeration of return values from application execution callout. The * action returned determines how the subsequent processing of the request * will proceed. */ public class UpdateAction { /** * Constructor. Creates an UpdateAction object from the status * and message components. * * @param status Indicates the status of execution of this update event. * This status may result in a state transition for the request. * * @param message A message that, depending on the value of {@code status}, * may be used for various purposes. */ public UpdateAction( AsyncStatus status, String message ); public AsyncStatus getAsyncStatus( ); public String getMessage( ); }
AsyncStatus
列挙が変更されました。
例16-14 Oracle Enterprise SchedulerのAsyncStatus列挙
Package oracle.as.scheduler.async; /** * Valid values for the callback status of an asynchronous java job. * Returning an {@code AsyncStatus} does not guarantee that the state of the * request will change to the corresponding value. The new state of the request * will depend on the old state, the async status, the result of the * post-Process handler (if any), and any errors that may occur in * subsequent processing. */ public enum AsyncStatus { /** * The asynchronous job ran successfully. */ SUCCESS, /** * The asynchronous job has paused for the execution of sub-requests. */ PAUSE, /** * The asynchronous job is issuing a WARNING. */ WARNING, /** * The asynchronous job encountered an error. */ ERROR, /** * The asynchronous job has canceled its execution. Usually this * originates from a {@code RuntimeService.cancel} call. */ CANCEL, /** * The asynchronous job is updated. The request state is not changed * by this action. */ UPDATE } /** * The asynchronous job encountered a business error. */ BIZ_ERROR, /** * The asynchronous job requests manual recovery to complete the request. */ ERROR_MANUAL_RECOVERY;
例16-15 既存の非同期コールバックWebサービス操作
/** * Set the status of an Oracle Enterprise Scheduler asynchronous java job. * * @param requestExecutionContext A java.lang.String representing * an oracle.as.scheduler.RequestExecutionContext object. * @param status * @param statusMessage * An error message if the status is ERROR, * A business error message if the status is BIZ_ERROR, * A warning message if the status is WARNING, * A paused state if the status is PAUSED. * The value is ignored if the status is SUCCESS or CANCEL. * */ public void setAsyncRequestStatus( String requestExecutionContext, AsyncStatus status, String statusMessage ) throws RequestNotFoundException, RuntimeServiceException ;