BPL のエラー処理
ここでは、BPL ビジネス・プロセスでのエラー処理について説明します。BPL は、ビジネス・プロセスがエラーをスロー/キャッチできるようにするためのエラー・ハンドラ、およびエラーの発生原因となったアクションを元に戻すことによって、エラーから復帰する方法を指定するための補償ハンドラを備えています。
このエラー処理システムを、他のビジネス・ホストと通信する <call> 文と共に使用するときは、エラーの場合にターゲット・ビジネス・ホストがエラー・ステータスを返すことを確認します。エラーの場合でもターゲット・コンポーネントが成功を返すと、BPL プロセスは <catchhall> ロジックをトリガしません。
エラー処理で呼び出される BPL 要素は、<scope>、<throw>、<catch>、<catchall>、<compensate>、<compensationhandlers>、<compensationhandler>、および <faulthandlers> です。このトピックでは、これらの要素を紹介し、これらの要素が連携して、さまざまなエラー処理シナリオをサポートするしくみについて説明します。
システム・エラー - エラー処理なし
以下は、エラー状態を生成し、エラー処理を行わない BPL ビジネス・プロセスの例です。
この BPL ビジネス・プロセスは以下の処理を実行します。
-
最初の <trace> 要素がメッセージの before assign を生成します。
-
<assign> 要素が SomeProperty を式 1/0 と同じに設定しようとします。この試みによって 0 による除算システム・エラーが発生します。
-
ビジネス・プロセスが終了し、メッセージがイベント・ログに送信されます。
2 つ目の <trace> 要素が使用されることはありません。
イベント・ログ・エントリ
この場合、イベント・ログのエントリは以下のようになります。
背景情報は、"イベント・ログの表示" を参照してください。
この BPL 用の XData
この BPL は以下の XData ブロックによって定義されます。
XData BPL
{
<process language='objectscript'
request='Test.Scope.Request'
response='Test.Scope.Response' >
<sequence>
<trace value='"before assign"'/>
<assign property="SomeProperty" value="1/0"/>
<trace value='"after assign"'/>
</sequence>
</process>
}
システム・エラー - Catchall で対応
エラー処理に対応するため、BPL には <scope> と呼ばれる要素があります。スコープは一連のアクティビティのラッパです。このスコープには、1 つ以上のアクティビティ、1 つ以上のフォールト・ハンドラ、ゼロ個以上の補償ハンドラを含めることができます。フォールト・ハンドラの目的は、<scope> 内のアクティビティによって生成されるすべてのエラーをキャッチすることです。また、補償ハンドラを呼び出して、発生したエラーに対処することもできます。
下の例では、<scope> 内に <faulthandlers> ブロックを配置し、さらに <catchall> を追加しています。<scope> に <faulthandlers> 要素が含まれているため、長方形の中央を横切る水平点線が追加されます。この線の下側の領域に、<faulthandlers> の内容が表示されます。
この BPL ビジネス・プロセスは以下の処理を実行します。
-
最初の <trace> 要素がメッセージの before scope を生成します。
-
<scope> 要素はスコープの始まりです。
-
2 つ目の <trace> 要素がメッセージの before assign を生成します。
-
<assign> 要素が式 1/0 を評価しようとします。この試みによって 0 による除算システム・エラーが発生します。
-
これで、制御が <scope> 内で定義された <faulthandlers> に移ります。<scope> 長方形に、中央を横切る水平点線が追加されます。この点線の下側の領域に <faulthandlers> 要素の内容が表示されます。この場合は、<catch> が存在しませんが、<catchall> 要素が存在するため、ここに制御が移ります。
InterSystems IRIS® は、<assign> 要素の直後の <trace> 要素メッセージを無視することに注意してください。
<catchall> を掘り下げる場合は、以下を参照してください。
-
<catchall> 内部で、<trace> 要素がメッセージの in catchall faulthandler を生成します。
-
<catchall> 内部で、別の <trace> 要素が $System.Status メソッドと特殊変数の %Context と %LastError を使用してエラーの特性を調査するメッセージを生成します。詳細は、"イベント・ログ・エントリ" を参照してください。
-
<scope> が終わります。
-
最後の <trace> 要素がメッセージの after scope を生成します。
イベント・ログ・エントリ
この場合、イベント・ログのエントリは以下のようになります。
予期しないシステム・エラーが発生した場合、<scope> 内に <faulthandlers> ブロックがあるときは、システム・エラー - エラー処理なしの例とは異なり、イベント・ログにエントリが自動的には出力されません。ビジネス・プロセスが何を実行するかは、<faulthandlers> ブロックによって決定されます。この例では、エラーに関する情報を含む <trace> メッセージを出力します。実際のエラーを示すイベント・ログ・エントリは、<catchall> ブロック内の以下の文によって生成されます。
<trace value=
'"%LastError "_
$System.Status.GetErrorCodes(..%Context.%LastError)_
" : "_
$System.Status.GetOneStatusText(..%Context.%LastError)'
/>
BPL コンテキスト変数 %LastError には、常に %StatusOpens in a new tab 値が含まれます。<UNDEF> などの予期せぬシステム・エラーが発生した場合は、この %StatusOpens in a new tab 値がエラー “ObjectScript エラー” (コード 5002) および特殊変数 $ZERROR のテキストから作成されます。%LastError から対応するエラー・コードとテキストを取得するには、上に示すように、$System.Status の GetErrorCodes メソッドと GetOneStatusText メソッドを使用して、それらを <trace> 文字列に連結します。
この BPL 用の XData
この BPL は以下の XData ブロックによって定義されます。
XData BPL
{
<process language='objectscript'
request='Test.Scope.Request'
response='Test.Scope.Response' >
<sequence>
<trace value='"before scope"'/>
<scope>
<trace value='"before assign"'/>
<assign property="SomeProperty" value="1/0"/>
<trace value='"after assign"'/>
<faulthandlers>
<catchall>
<trace value='"in catchall faulthandler"'/>
<trace value=
'"%LastError "_
$System.Status.GetErrorCodes(..%Context.%LastError)_
" : "_
$System.Status.GetOneStatusText(..%Context.%LastError)'
/>
</catchall>
</faulthandlers>
</scope>
<trace value='"after scope"'/>
</sequence>
</process>
}
フォールトをスロー - Catchall で対応
<throw> 文を実行するとき、その fault 値は結果が文字列となる式です。Java のような他のオブジェクト指向言語と異なり、フォールトはオブジェクトではなく、文字列値です。フォールト文字列を指定するときは、以下のように、1 組の引用符を余分に追加する必要があります。
<throw fault='"thrown"'/>
<throw> 文が実行されると、即座に、同じ <scope> 内の <faulthandlers> ブロックに制御が移り、<throw> 以降の途中の文はすべて省略されます。次にプログラムは、<faulthandlers> ブロック内で、<throw> 文の fault 文字列式と value 属性が同じである <catch> ブロックを探します。この比較では大文字と小文字が区別されます。
フォールトと一致する <catch> ブロックが見つかった場合は、その <catch> ブロック内のコードを実行して、<scope> から抜けます。終わりの </scope> 要素の次の文から実行を再開します。
フォールトがスローされ、フォールト文字列と一致する <catch> ブロックが <faulthandlers> ブロック内に存在しない場合は、制御が <throw> 文から <faulthandlers> 内の <catchall> ブロックに移ります。<catchall> ブロック内のコードを実行した後で、<scope> から抜けます。終わりの </scope> 要素の次の文から実行を再開します。予期しないエラーを確実にキャッチするため、すべての <faulthandlers> ブロック内に <catchall> ブロックを配置することをお勧めします。
以下の BPL があるとします。スペースの関係で、<start> 要素と <end> 要素が表示されていません。
この BPL ビジネス・プロセスは以下の処理を実行します。
-
最初の <trace> 要素がメッセージの before scope を生成します。
-
<scope> 要素はスコープの始まりです。
-
2 つ目の <trace> 要素がメッセージの before assign を生成します。
-
<throw> 要素が特定の名前付きフォールト ("MyFault") をスローします。
-
これで、制御が <scope> 内で定義された <faulthandlers> に移ります。<scope> 長方形に、中央を横切る水平点線が追加されます。この点線の下側の領域に <faulthandlers> 要素の内容が表示されます。この場合は、<catch> が存在しませんが、<catchall> 要素が存在するため、ここに制御が移ります。
InterSystems IRIS は 3 つ目の <trace> 要素を無視することに注意してください。
<catchall> を掘り下げる場合は、以下を参照してください。
-
<catchall> 内部で、最初の <trace> 要素がメッセージの in catchall faulthandler を生成します。
-
<catchall> 内部で、2 つ目の <trace> 要素が $System.Status メソッドと特殊変数の %Context と %LastError を使用してフォールトに関する情報を提供するメッセージを生成します。フォールトがスローされた結果としての %LastError は、システム・エラーの結果としての値と異なります。
-
GetErrorCodes は <Ens>ErrBPLThrownFault を返します。
-
GetOneStatusText は、<throw> 文の fault 式から得られたテキストを返します。
-
-
<catchall> 内部で、3 つ目の <trace> 要素が BPL コンテキスト変数の %LastFault を使用してフォールトに関する情報を提供するメッセージを生成します。このメッセージには、<throw> 文の fault 式から得られたテキストが含まれます。
-
<scope> が終わります。
-
最後の <trace> 要素がメッセージの after scope を生成します。
イベント・ログ・エントリ
この場合、イベント・ログのエントリは以下のようになります。
この BPL 用の XData
この BPL は以下の XData ブロックによって定義されます。
XData BPL
{
<process language='objectscript'
request='Test.Scope.Request'
response='Test.Scope.Response' >
<sequence>
<trace value='"before scope"'/>
<scope>
<trace value='"before assign"'/>
<throw fault='"MyFault"'/>
<trace value='"after assign"'/>
<faulthandlers>
<catchall>
<trace value='"in catchall faulthandler"'/>
<trace value=
'"%LastError "_
$System.Status.GetErrorCodes(..%Context.%LastError)_
" : "_
$System.Status.GetOneStatusText(..%Context.%LastError)'
/>
<trace value='"%LastFault "_..%Context.%LastFault'/>
</catchall>
</faulthandlers>
</scope>
<trace value='"after scope"'/>
</sequence>
</process>
}
フォールトをスロー - Catch で対応
前述の例のように、スローされたフォールトを <catchall> で処理する以外に、特定の <catch> を使用することもできます。
以下の BPL があるとします。
この BPL ビジネス・プロセスは以下の処理を実行します。
-
最初の <trace> 要素がメッセージの before scope を生成します。
-
<scope> 要素はスコープの始まりです。
-
2 つ目の <trace> 要素がメッセージの before throw を生成します。
-
<throw> 要素が特定の名前付きフォールト ("MyFault") をスローします。
-
これで、制御が <scope> 内で定義された <faulthandlers> に移ります。<scope> 長方形に、中央を横切る水平点線が追加されます。この点線の下側の領域に <faulthandlers> 要素の内容が表示されます。この場合は、fault 値が "MyFault" の <catch> 要素が存在するため、ここに制御が移ります。<catchall> 要素は無視されます。
InterSystems IRIS は、<throw> 要素以降の <trace> 要素メッセージを無視することに注意してください。
<catch> を掘り下げる場合は、以下を参照してください。
Note:<catchall> を設ける場合は、それを <faulthandlers> ブロックの最後の文にする必要があります。必ず、<catchall> の前にすべての <catch> ブロックを配置します。
-
<catch> 内部で、<trace> 要素がメッセージの in catch faulthandler for ‘MyFault’ を生成します。
-
<scope> が終わります。
-
最後の <trace> 要素がメッセージの after scope を生成します。
イベント・ログ・エントリ
この場合、イベント・ログのエントリは以下のようになります。
この BPL 用の XData
この BPL は以下の XData ブロックによって定義されます。
XData BPL
{
<process language='objectscript'
request='Test.Scope.Request'
response='Test.Scope.Response' >
<sequence>
<trace value='"before scope"'/>
<scope>
<trace value='"before throw"'/>
<throw fault='"MyFault"'/>
<trace value='"after throw"'/>
<faulthandlers>
<catch fault='"MyFault"'>
<trace value='"In catch faulthandler for 'MyFault'"'/>
</catch>
<catchall>
<trace value='"in catchall faulthandler"'/>
<trace value=
'"%LastError "_
$System.Status.GetErrorCodes(..%Context.%LastError)_
" : "_
$System.Status.GetOneStatusText(..%Context.%LastError)'
/>
<trace value='"%LastFault "_..%Context.%LastFault'/>
</catchall>
</faulthandlers>
</scope>
<trace value='"after scope"'/>
</sequence>
</process>
}
ネスト構造のスコープ - 内側のフォールト・ハンドラに Catchall を配置
<scope> 要素をネスト構造にできます。内側のスコープでエラーやフォールトが発生した場合、内側のスコープ内でキャッチする方法と、内側のスコープはそのエラーを無視し、外側スコープの <faulthandlers> ブロックでキャッチする方法があります。この後のトピックでは、複数のスコープがネストされているとき、内側のスコープで発生したエラーやフォールトを BPL がどのように処理するかを説明します。
以下の BPL があるとします (ここでは、<start> 要素と <end> 要素が省略されています)。
この BPL ビジネス・プロセスは以下の処理を実行します。
-
最初の <trace> 要素がメッセージの before outer scope を生成します。
-
最初の <scope> 要素は外側のスコープの始まりです。
-
2 つ目の <trace> 要素がメッセージの in outer scope, before inner scope を生成します。
-
2 つ目の <scope> 要素は内側のスコープの始まりです。
-
次の <trace> 要素がメッセージの in inner scope, before assign を生成します。
-
<assign> 要素が式 1/0 を評価しようとします。この試みによって 0 による除算システム・エラーが発生します。
-
これで、制御が内側の <scope> 内で定義された <faulthandlers> に移ります。この <scope> 長方形に、中央を横切る水平点線が追加されます。この点線の下側の領域に <faulthandlers> 要素の内容が表示されます。この場合は、<catch> が存在しませんが、<catchall> が存在するため、ここに制御が移ります。
InterSystems IRIS は、<assign> 要素の直後の <trace> 要素を無視することに注意してください。
この <catchall> を掘り下げる場合は、以下を参照してください。
-
<catchall> 内部で、<trace> 要素がメッセージの in inner scope, catchall を生成します。
-
内側の <scope> が終わります。
-
次の <trace> 要素がメッセージの in outer scope, after inner scope を生成します。
-
外側の <scope> 長方形に、中央を横切る水平点線が追加されます。この点線の下側の領域に <catchall> を含む <faulthandlers> 要素の内容が表示されます。フォールトが存在しないため、この <catchall> は無視されます。
-
外側の <scope> が終わります。
-
最後の <trace> 要素がメッセージの after outer scope を生成します。
イベント・ログ・エントリ
この場合、イベント・ログのエントリは以下のようになります。
この BPL 用の XData
この BPL は以下の XData ブロックによって定義されます。
XData BPL
{
<process language='objectscript'
request='Test.Scope.Request'
response='Test.Scope.Response' >
<sequence>
<trace value='"before outer scope"'/>
<scope>
<trace value='"in outer scope, before inner scope"'/>
<scope>
<trace value='"in inner scope, before assign"'/>
<assign property="SomeProperty" value="1/0"/>
<trace value='"in inner scope, after assign"'/>
<faulthandlers>
<catchall>
<trace value='"in inner scope, catchall"'/>
</catchall>
</faulthandlers>
</scope>
<trace value='"in outer scope, after inner scope"'/>
<faulthandlers>
<catchall>
<trace value='"in outer scope, catchall"'/>
</catchall>
</faulthandlers>
</scope>
<trace value='"after outer scope"'/>
</sequence>
</process>
}
ネスト構造のスコープ - 外側のフォールト・ハンドラに Catchall を配置
以下の BPL があるとします (部分的に表示されています)。
この BPL の残りを以下に示します。
この BPL ビジネス・プロセスは以下の処理を実行します。
-
最初の <trace> 要素がメッセージの before outer scope を生成します。
-
最初の <scope> 要素は外側のスコープの始まりです。
-
次の <trace> 要素がメッセージの in outer scope, before inner scope を生成します。
-
2 つ目の <scope> 要素は内側のスコープの始まりです。
-
次の <trace> 要素がメッセージの in inner scope, before assign を生成します。
-
<assign> 要素が式 1/0 を評価しようとします。この試みによって 0 による除算システム・エラーが発生します。
-
これで、制御が内側の <scope> 内で定義された <faulthandlers> に移ります。この <scope> 長方形に、中央を横切る水平点線が追加されます。この点線の下側の領域に <faulthandlers> 要素の内容が表示されます。この場合は、<catch> が存在しますが、その fault 値が、スローされたフォールトと一致しません。内側のスコープには <catchall> がありません。
InterSystems IRIS は、<assign> の直後の <trace> 要素を無視することに注意してください。
-
これで、制御が外側の <scope> 内の <faulthandlers> ブロックに移ります。どの <catch> もフォールトと一致しませんが、<catchall> ブロックがあります。制御がこの <catchall> に移ります。
この <catchall> を掘り下げる場合は、以下を参照してください。
-
<catchall> 内部で、<trace> 要素がメッセージの in inner scope, catchall を生成します。
-
外側の <scope> が終わります。
-
最後の <trace> 要素がメッセージの after outer scope を生成します。
イベント・ログ・エントリ
この場合、イベント・ログのエントリは以下のようになります。
この BPL 用の XData
この BPL は以下の XData ブロックによって定義されます。
XData BPL
{
<process language='objectscript'
request='Test.Scope.Request'
response='Test.Scope.Response' >
<sequence>
<trace value='"before outer scope"'/>
<scope>
<trace value='"in outer scope, before inner scope"'/>
<scope>
<trace value='"in inner scope, before assign"'/>
<assign property="SomeProperty" value="1/0"/>
<trace value='"in inner scope, after assign"'/>
<faulthandlers>
<catch fault='"MismatchedFault"'>
<trace value=
'"In catch faulthandler for 'MismatchedFault'"'/>
</catch>
</faulthandlers>
</scope>
<trace value='"in outer scope, after inner scope"'/>
<faulthandlers>
<catchall>
<trace value='"in outer scope, catchall"'/>
</catchall>
</faulthandlers>
</scope>
<trace value='"after outer scope"'/>
</sequence>
</process>
}
ネスト構造のスコープ - どのスコープでも一致しない場合
以下の BPL があるとします (部分的に表示されています)。
この BPL の残りを以下に示します。
この BPL ビジネス・プロセスは以下の処理を実行します。
-
最初の <trace> 要素がメッセージの before outer scope を生成します。
-
最初の <scope> 要素は外側のスコープの始まりです。
-
次の <trace> 要素がメッセージの in outer scope, before inner scope を生成します。
-
2 つ目の <scope> 要素は内側のスコープの始まりです。
-
次の <trace> 要素がメッセージの in inner scope, before assign を生成します。
-
<assign> 要素が式 1/0 を評価しようとします。この試みによって 0 による除算システム・エラーが発生します。
-
これで、制御が内側の <scope> 内の <faulthandlers> ブロックに移ります。<scope> 長方形に、中央を横切る水平点線が追加されます。この点線の下側の領域に <faulthandlers> 要素の内容が表示されます。この場合は、<catch> が存在しますが、その fault 値が、スローされたフォールトと一致しません。内側のスコープには <catchall> がありません。
-
これで、制御が外側の <scope> 内の <faulthandlers> ブロックに移ります。どの <catch> もフォールトと一致しません。また、<catchall> ブロックもありません。
-
BPL が即座に停止して、メッセージがイベント・ログに送信されます。
イベント・ログ・エントリ
この場合、イベント・ログのエントリは以下のようになります。
このイベント・ログと、システム・エラー - エラー処理なしの例で紹介したイベント・ログとの間には重要な相違点があります。これら 2 つの例の共通点は、ゼロによる除算のエラーが発生した場合の適切なフォールト処理が設けられていないことです。
ただし、システム・エラー - エラー処理なしの例には <scope> がなく、<faulthandlers> ブロックもありません。このような状況では、最初の例で示したように、InterSystems IRIS は、自動的に、システム・エラーをイベント・ログに出力します。
一方、上記の例では、各 <scope> に <faulthandlers> ブロックが含まれています。このような場合は、システム・エラー - エラー処理なしの例と異なり、イベント・ログにシステム・エラーが自動的には出力されません。予期しないエラーが発生したとき <trace> メッセージをイベント・ログに出力するかどうかは、BPL ビジネス・プロセス開発者が決定します。この例には、フォールトをキャッチする <faulthandlers> ブロックがありません。ビジネス・プロセスの終了に関する自動メッセージには、システム・エラーのトレース情報のみが含まれます (上記の 4 番)。
システム・エラー・メッセージが ObjectScript シェルに表示されます。
ERROR #5002: ObjectScript error: <DIVIDE>zS4+3^Test.Scope.BusinessProcess.Thread1.1
この BPL 用の XData
この BPL は以下の XData ブロックによって定義されます。
XData BPL
{
<process language='objectscript'
request='Test.Scope.Request'
response='Test.Scope.Response' >
<sequence>
<trace value='"before outer scope"'/>
<scope>
<trace value='"in outer scope, before inner scope"'/>
<scope>
<trace value='"in inner scope, before assign"'/>
<assign property="SomeProperty" value="1/0"/>
<trace value='"in inner scope,after assign"'/>
<faulthandlers>
<catch fault='"MismatchedFault"'>
<trace value=
'"In catch faulthandler for 'MismatchedFault'"'/>
</catch>
</faulthandlers>
</scope>
<trace value='"in outer scope, after inner scope"'/>
<faulthandlers>
<catch fault='"MismatchedFault"'>
<trace value=
'"In catch faulthandler for 'MismatchedFault'"'/>
</catch>
</faulthandlers>
</scope>
<trace value='"after outer scope"'/>
</sequence>
</process>
}
ネスト構造のスコープ - 外側のフォールト・ハンドラに Catch を配置
以下の BPL があるとします (部分的に表示されています)。
この BPL の残りを以下に示します。
この BPL ビジネス・プロセスは以下の処理を実行します。
-
最初の <trace> 要素がメッセージの before outer scope を生成します。
-
最初の <scope> 要素は外側のスコープの始まりです。
-
次の <trace> 要素がメッセージの in outer scope, before inner scope を生成します。
-
2 つ目の <scope> 要素は内側のスコープの始まりです。
-
次の <trace> 要素がメッセージの in inner scope, before throw を生成します。
-
<throw> 要素が特定の名前付きフォールト ("MyFault") をスローします。
-
これで、制御が内側の <scope> 内で定義された <faulthandlers> に移ります。<catch> は存在しますが、その fault 値は "MismatchedFault" です。内側のスコープには <catchall> がありません。
-
制御が外側の <scope> 内の <faulthandlers> ブロックに移ります。このブロックには、fault 値が "MyFault" の <catch> が含まれます。
-
次の <trace> 要素がメッセージの in outer scope catch faulthandler for 'MyFault' を生成します。
-
2 つ目の <scope> が終わります。
-
最後の <trace> 要素がメッセージの after outer scope を生成します。
イベント・ログ・エントリ
この場合、イベント・ログのエントリは以下のようになります。
この BPL 用の XData
この BPL は以下の XData ブロックによって定義されます。
XData BPL
{
<process language='objectscript'
request='Test.Scope.Request'
response='Test.Scope.Response' >
<sequence>
<trace value='"before outer scope"'/>
<scope>
<trace value='"in outer scope, before inner scope"'/>
<scope>
<trace value='"in inner scope, before throw"'/>
<throw fault='"MyFault"'/>
<trace value='"in inner scope, after throw"'/>
<faulthandlers>
<catch fault='"MismatchedFault"'>
<trace value=
'"In inner scope catch faulthandler for 'MismatchedFault'"'/>
</catch>
</faulthandlers>
</scope>
<trace value='"in outer scope, after inner scope"'/>
<faulthandlers>
<catch fault='"MyFault"'>
<trace value=
'"In outer scope catch faulthandler for 'MyFault'"'/>
</catch>
</faulthandlers>
</scope>
<trace value='"after outer scope"'/>
</sequence>
</process>
}
フォールトをスロー - 補償ハンドラで対応
ビジネス・プロセス管理では、一部のロジック・セグメントを元に戻す必要が頻繁に生じます。この処理を “補償” といいます。原則として、ビジネス・プロセスが何かを実行する場合、その操作を取り消すことができる必要があります。つまり、エラーが発生した場合、ビジネス・プロセスは失敗した操作を元に戻すことによって、そのエラーを補償できる必要があります。障害発生時点以降のすべての操作を取り消し、問題が発生しなかった場合と同じ状態に戻す必要があります。BPL では、補償ハンドラと呼ばれるしくみによってこれを実現します。
BPL <compensationhandler> ブロックはサブルーチンに似ていますが、一般的なサブルーチン・メカニズムを備えていません。これらのブロックを “呼び出す” ことは可能ですが、必ず<faulthandler> ブロックから呼び出すこと、かつ、必ずその <compensationhandler> ブロックと同じ <scope> 内から呼び出すことが条件となります。<compensate> 要素から <compensationhandler> ブロックを呼び出すときは、ターゲットとしてその名前を指定します。この構文では、引用符を追加する必要がありません。
<compensate target="general"/>
補償ハンドラが役に立つのは、既に実行されている処理を元に戻せる場合だけです。例えば、預金を間違った口座に振り替えた場合、元の口座に振り替え直すことは可能ですが、元どおりの状態にできない処理もあります。したがって、適切な補償ハンドラを計画し、どの程度後退するのかに応じて、それらの補償ハンドラを構成する必要があります。
以下の BPL があるとします。
この BPL ビジネス・プロセスは以下の処理を実行します。
-
[コンテキスト] タブ (非表示) は、MyBalance という名前のプロパティを定義して、その値を 100 に設定します。
-
最初の <trace> 要素がメッセージの before scope balance is を生成し、その後に MyBalance の値が続きます。
-
<scope> 要素はスコープの始まりです。
-
次の <trace> 要素がメッセージの before debit を生成します。
-
<assign> 要素が MyBalance を 1 減らします。
-
次の <trace> 要素がメッセージの after debit を生成します。
-
<throw> 要素が特定の名前付きフォールト ("BuyersRegret") をスローします。
-
これで、制御が <faulthandlers> に移ります。fault 値が "BuyersRegret" の <catch> が存在するため、ここに制御が移ります。
この <catch> 要素を掘り下げる場合は、以下を参照してください。
-
この <catch> 内部で、<trace> 要素がメッセージの in catch faulthandler for 'BuyersRegret' を生成します。
-
この <catch> 内部で、2 つ目の <trace> 要素がメッセージの before restore balance is を生成し、その後ろに MyBalance の現在値が続きます。
-
<compensate> 要素が使用されます。この要素の場合は、target が、name が RestoreBalance の <compensationhandler> です。この <compensationhandler> ブロックで以下の処理を実行します。
-
<trace> 文により、メッセージ “Restoring Balance” を出力します。
-
<assign> 文を実行して、MyBalance を 1 増やします。
Note:<compensationhandlers> と <faulthandlers> の順序を逆にすることはできません。これら両方のブロックを記述する場合は、最初に <compensationhandlers>、次に <faulthandlers> を配置する必要があります。
-
-
次の <trace> 要素がメッセージの after restore balance is を生成し、その後に MyBalance の現在値が続きます。
-
<scope> が終わります。
-
最後の <trace> 要素がメッセージの after scope balance is を生成し、その後に MyBalance の現在値が続きます。
イベント・ログ・エントリ
この場合、イベント・ログのエントリは以下のようになります。
この BPL 用の XData
この BPL は以下の XData ブロックによって定義されます。
XData BPL
{
<process language='objectscript'
request='Test.Scope.Request'
response='Test.Scope.Response' >
<context>
<property name="MyBalance" type="%Library.Integer" initialexpression='100'/>
</context>
<sequence>
<trace value='"before scope balance is "_context.MyBalance'/>
<scope>
<trace value='"before debit"'/>
<assign property='context.MyBalance' value='context.MyBalance-1'/>
<trace value='"after debit"'/>
<throw fault='"BuyersRegret"'/>
<compensationhandlers>
<compensationhandler name="RestoreBalance">
<trace value='"Restoring Balance"'/>
<assign property='context.MyBalance' value='context.MyBalance+1'/>
</compensationhandler>
</compensationhandlers>
<faulthandlers>
<catch fault='"BuyersRegret"'>
<trace value='"In catch faulthandler for 'BuyersRegret'"'/>
<trace value='"before restore balance is "_context.MyBalance'/>
<compensate target="RestoreBalance"/>
<trace value='"after restore balance is "_context.MyBalance'/>
</catch>
<catchall>
<trace value='"in catchall faulthandler"'/>
<trace value=
'"%LastError "_
$System.Status.GetErrorCodes(..%Context.%LastError)_
" : "_
$System.Status.GetOneStatusText(..%Context.%LastError)'
/>
<trace value='"%LastFault "_..%Context.%LastFault'/>
</catchall>
</faulthandlers>
</scope>
<trace value='"after scope balance is "_context.MyBalance'/>
</sequence>
</process>
}