Skip to main content

Handling Errors in BPL

This topic explains how BPL business processes support error handling. BPL provides fault handlers that allow your business process to throw and catch errors, and compensation handlers that allow your business process to specify how it recovers from errors by undoing the actions that led to the error condition.

Important:

When you use this error handling system with <call> statements that communicate with other business hosts, make sure that the target business hosts return an error status in the case of an error. If the target component returns success even in the case of an error, the BPL process will not trigger <catchall> logic.

The BPL elements involved in error handling are <scope>, <throw>, <catch>, <catchall>, <compensate>, <compensationhandlers>, <compensationhandler>, and <faulthandlers>. This topic introduces these elements and explains how they work together to support the different error handling scenarios.

System Error with No Fault Handling

The following is an example of a BPL business process that produces an error condition and provides no error handling:

BPL diagram with the following shapes in order: start, empty trace, assign, empty trace, end

This BPL business process does the following:

  1. The first <trace> element generates the message before assign.

  2. The <assign> element tries to set SomeProperty equal to the expression 1/0. This attempt produces a divide-by-zero system error.

  3. The business process ends and sends a message to the Event Log.

    The second <trace> element is never used.

Event Log Entries

The corresponding Event Log entries look like this.

Two error messages stacked on top of each other

For background information, see Event Log.

XData for This BPL

This BPL is defined by the following XData block:

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>
}

System Error with Catchall

To enable error handling, BPL defines an element called <scope>. A scope is a wrapper for a set of activities. This scope may contain one or more activities, one or more fault handlers, and zero or more compensation handlers. The fault handlers are intended to catch any errors that activities within the <scope> produce. The fault handlers may invoke compensation handlers to compensate for those errors.

The following example provides a <scope> with a <faulthandlers> block that includes a <catchall>. Because the <scope> includes a <faulthandlers> element, the rectangle includes a horizontal dashed line across the middle; the area below this line displays the contents of the <faulthandlers>.

BPL diagram showing a rectangle with a dotted line across the middle surrounding several elements

This BPL business process does the following:

  1. The first <trace> element generates the message before scope.

  2. The <scope> element starts the scope.

  3. The second <trace> element generates the message before assign.

  4. The <assign> element tries to evaluate the expression 1/0. This attempt produces a divide-by-zero system error.

  5. Control now goes to the <faulthandlers> defined within the <scope>. The <scope> rectangle includes a horizontal dashed line across the middle; the area below this dashed line displays the contents of the <faulthandlers> element. In this case, there is no <catch>, but there is a <catchall> element, so control goes there.

    Note that InterSystems IRIS® skips the <trace> element message immediately after the <assign> element.

    If we drill down into <catchall>, we see this:

    BPL diagram with the following elements in order: start, trace, trace, end

  6. Within <catchall>, a <trace> element generates the message in catchall faulthandler.

  7. Within <catchall>, another <trace> element generates a message that explores the nature of the error using $System.Status methods and the special variables %Context and %LastError. See the details in Event Log Entries.

  8. The <scope> ends.

  9. The last <trace> element generates the message after scope.

Event Log Entries

The corresponding Event Log entries look like this.

Error message stacked above a log entry for in catchall faulthandler

If an unexpected system error occurs, and a <faulthandlers> block is present inside a <scope>, the BPL business process does not automatically place entries in the Event Log as shown in the System Error with No Fault Handling example. Rather, the <faulthandlers> block determines what the business process will do. In the current example, it outputs a <trace> message that contains information about the error. The Event Log entry showing the actual error is produced by the following statement within the <catchall> block:

<trace value=
  '"%LastError "_
  $System.Status.GetErrorCodes(..%Context.%LastError)_
  " : "_
  $System.Status.GetOneStatusText(..%Context.%LastError)'
  />

The BPL context variable %LastError always contains a %StatusOpens in a new tab value. If the error was an unexpected system error such as <UNDEF> this %StatusOpens in a new tab value is created from the error “ObjectScript error” which has code 5002, and the text of the $ZERROR special variable. To get the corresponding error code and text out of %LastError, use the $System.Status methods GetErrorCodes and GetOneStatusText, then concatenate them into a <trace> string, as shown above.

XData for This BPL

This BPL is defined by the following XData block:

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>
}

Thrown Fault with Catchall

When a <throw> statement executes, its fault value is an expression that evaluates to a string. Faults are not objects, as in other object-oriented languages such as Java; they are string values. When you specify a fault string it needs the extra set of quotes to contain it, as shown below:

<throw fault='"thrown"'/>

When a <throw> statement executes, control immediately goes to the <faulthandlers> block inside the same <scope>, skipping all intervening statements after the <throw>. Inside the <faulthandlers> block, the program attempts to find a <catch> block whose value attribute matches the fault string expression in the <throw> statement. This comparison is case-sensitive.

If there is a <catch> block that matches the fault, the program executes the code within this <catch> block and then exits the <scope>. The program resumes execution at the next statement following the closing </scope> element.

If a fault is thrown, and the corresponding <faulthandlers> block contains no <catch> block that matches the fault string, control goes from the <throw> statement to the <catchall> block inside <faulthandlers>. After executing the contents of the <catchall> block, the program exits the <scope>. The program resumes execution at the next statement following the closing </scope> element. It is good programming practice to ensure that there is always a <catchall> block inside every <faulthandlers> block, to ensure that the program catches any unanticipated errors.

Suppose you have the following BPL. For reasons of space, the <start> and <end> elements are not shown.

BPL diagram with several shapes surrounded by a rectangle with a dashed line in the middle

This BPL business process does the following:

  1. The first <trace> element generates the message before scope.

  2. The <scope> element starts the scope.

  3. The second <trace> element generates the message before assign.

  4. The <throw> element throws a specific, named fault ("MyFault").

  5. Control now goes to the <faulthandlers> defined within the <scope>. The <scope> rectangle includes a horizontal dashed line across the middle; the area below this dashed line displays the contents of the <faulthandlers> element. In this case, there is no <catch> but there is a <catchall> element, so control goes there.

    Note that InterSystems IRIS skips the third <trace> element.

    If we drill down into <catchall>, we see this:

    BPL diagram with the following elements in order: start, trace, trace, trace, end

  6. Within <catchall>, the first <trace> element generates the message in catchall faulthandler.

  7. Within <catchall>, the second <trace> element generates the message that provides information on the fault using $System.Status methods and the special variables %Context and %LastError. The %LastError value as the result of a thrown fault is different from its value as the result of a system error:

    • GetErrorCodes returns <Ens>ErrBPLThrownFault

    • GetOneStatusText returns text derived from the fault expression in the <throw> statement

  8. Within <catchall>, the third <trace> element generates a message that provides information on the fault using the BPL context variable %LastFault. It contains the text derived from the fault expression from the <throw> statement.

  9. The <scope> ends.

  10. The last <trace> element generates the message after scope.

Event Log Entries

The corresponding Event Log entries look like this:

Error message stacked above in catchall faulthandler

XData for This BPL

This BPL is defined by the following XData block:

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>
}

Thrown Fault with Catch

A thrown fault may reach a <catchall>, as in the previous example, or it may have a specific <catch>.

Suppose you have the following BPL:

BPL diagram with several shapes surrounded by a rectangle that has a dashed line in the middle

This BPL business process does the following:

  1. The first <trace> element generates the message before scope.

  2. The <scope> element starts the scope.

  3. The second <trace> element generates the message before throw.

  4. The <throw> element throws a specific, named fault ("MyFault").

  5. Control now goes to the <faulthandlers> defined within the <scope>. The <scope> rectangle includes a horizontal dashed line across the middle; the area below this dashed line displays the contents of the <faulthandlers> element. In this case, a <catch> element exists whose fault value is "MyFault", so control goes there. The <catchall> element is ignored.

    Note that InterSystems IRIS skips the <trace> element message after the <throw> element.

    If we drill down into <catch>, we see this:

    BPL diagram with the following shapes in order: start, trace, end

    Note:

    If a <catchall> is provided, it must be the last statement in the <faulthandlers> block. All <catch> blocks must appear before <catchall>.

  6. Within <catch>, the <trace> element generates the message in catch faulthandler for ‘MyFault’.

  7. The <scope> ends.

  8. The last <trace> element generates the message after scope.

Event Log Entries

The corresponding Event Log entries look like this:

Event log with entries for before scope, before throw, in catchall faulthandler, and after scope

XData for This BPL

This BPL is defined by the following XData block:

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 &apos;MyFault&apos;"'/>
        </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>
}

Nested Scopes, Inner Fault Handler Has Catchall

It is possible to nest <scope> elements. An error or fault that occurs within the inner scope may be caught within the inner scope, or the inner scope may ignore the error and allow it to be caught by the <faulthandlers> block in the outer scope. The next several topics illustrate how BPL handles errors and faults that occur within an inner scope, when two or more scopes are nested.

Suppose you have the following BPL (shown here without the <start> and <end> elements):

Complex BPL diagram with nested scope shapes, resulting in nested rectangles

This BPL business process does the following:

  1. The first <trace> element generates the message before outer scope.

  2. The first <scope> element starts the outer scope.

  3. The second <trace> element generates the message in outer scope, before inner scope.

  4. The second <scope> element starts the inner scope.

  5. The next <trace> element generates the message in inner scope, before assign.

  6. The <assign> element tries to evaluate the expression 1/0. This attempt produces a divide-by-zero system error.

  7. Control now goes to the <faulthandlers> defined within the inner <scope>. This <scope> rectangle includes a horizontal dashed line across the middle; the area below this dashed line displays the contents of the <faulthandlers> element. In this case, there is no <catch> but there is a <catchall>, so control goes there.

    Note that InterSystems IRIS skips the <trace> element immediately after the <assign> element.

    If we drill into this <catchall>, we see this:

    BPL diagram with the following shapes in order: start, trace, end

  8. Within this <catchall>, the <trace> element generates the message in inner scope, catchall.

  9. The inner <scope> ends.

  10. The next <trace> element generates the message in outer scope, after inner scope.

  11. The outer <scope> rectangle includes a horizontal dashed line across the middle; the area below this dashed line displays the contents of the <faulthandlers> element that contains a <catchall>. Because there is no fault, this <catchall> is ignored.

  12. The outer <scope> ends.

  13. The last <trace> element generates the message after outer scope.

Event Log Entries

The corresponding Event Log entries look like this:

Event log showing that nested scopes are identified with the terms inner scope and outer scope

XData for This BPL

This BPL is defined by the following XData block:

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>
}

Nested Scopes, Outer Fault Handler Has Catchall

Suppose you have the following BPL (partially shown):

Partial BPL diagram with nested scope elements

The rest of this BPL is as follows:

Partial BPL diagram with five shapes: trace, catchall, join, trace, end

This BPL business process does the following:

  1. The first <trace> element generates the message before outer scope.

  2. The first <scope> element starts the outer scope.

  3. The next <trace> element generates the message in outer scope, before inner scope.

  4. The second <scope> element starts the inner scope.

  5. The next <trace> element generates the message in inner scope, before assign.

  6. The <assign> element tries to evaluate the expression 1/0. This attempt produces a divide-by-zero system error.

  7. Control now goes to the <faulthandlers> defined within the inner <scope>. This <scope> rectangle includes a horizontal dashed line across the middle; the area below this dashed line displays the contents of the <faulthandlers> element. In this case, a <catch> exists, but its fault value does not match the thrown fault. There is no <catchall> in the inner scope.

    Note that InterSystems IRIS skips the <trace> element that is immediately after <assign>.

  8. Control now goes to the <faulthandlers> block in the outer <scope>. No <catch> matches the fault, but there is a <catchall> block. Control goes to this <catchall>.

    If we drill into this <catchall>, we see this:

    BPL diagram with the following shapes in order: start, trace, end

  9. Within this <catchall>, the <trace> element generates the message in outer scope, catchall.

  10. The outer <scope> ends.

  11. The last <trace> element generates the message after outer scope.

Event Log Entries

The corresponding Event Log entries look like this:

Event log with entries for inner and outer scope elements

XData for This BPL

This BPL is defined by the following XData block:

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 &apos;MismatchedFault&apos;"'/>
          </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>
}

Nested Scopes, No Match in Either Scope

Suppose you have the following BPL (partially shown):

BPL diagram with nested scopes

The rest of this BPL is as follows:

Partial BPL diagram with the following elements in order: trace, catch, join, trace, end

This BPL business process does the following:

  1. The first <trace> element generates the message before outer scope.

  2. The first <scope> element starts the outer scope.

  3. The next <trace> element generates the message in outer scope, before inner scope.

  4. The second <scope> element starts the inner scope.

  5. The next <trace> element generates the message in inner scope, before assign.

  6. The <assign> element tries to evaluate the expression 1/0. This attempt produces a divide-by-zero system error.

  7. Control now goes to the <faulthandlers> block in the inner <scope>. The <scope> rectangle includes a horizontal dashed line across the middle; the area below this dashed line displays the contents of the <faulthandlers> element. In this case, a <catch> exists, but its fault value does not match the thrown fault. There is no <catchall> in the inner scope.

  8. Control now goes to the <faulthandlers> block in the outer <scope>. No <catch> matches the fault, and there is no <catchall> block.

  9. The BPL immediately stops, sending a message to the Event Log.

Event Log Entries

The corresponding Event Log entries look like this.

Event log with error after inner scope and before assign elements

There is an important difference between this Event Log and the one in the System Error with No Fault Handling example. The two examples have this in common: Each fails to provide adequate fault handling for the case when the divide-by-zero error occurs.

The difference is that the System Error with No Fault Handling example has no <scope> and no <faulthandlers> block. Under these circumstances, InterSystems IRIS automatically outputs the system error to the Event Log, as shown in the first example.

The current example is different because each <scope> does include a <faulthandlers> block. Under these circumstances, InterSystems IRIS does not automatically output the system error to the Event Log, as it did in the System Error with No Fault Handling example. It is up to the BPL business process developer to decide to output <trace> messages to the Event Log in case of an unexpected error. In the current example, no <faulthandlers> block catches the fault, so the only information that is traced regarding the system error is contained in the automatic message about business process termination (item 4 above).

The system error message does appear in the ObjectScript shell:

ERROR #5002: ObjectScript error: <DIVIDE>zS4+3^Test.Scope.BusinessProcess.Thread1.1

XData for This BPL

This BPL is defined by the following XData block:

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 &apos;MismatchedFault&apos;"'/>
          </catch>
        </faulthandlers>
      </scope>
      <trace value='"in outer scope, after inner scope"'/>
      <faulthandlers>
        <catch fault='"MismatchedFault"'>
          <trace value=
            '"In catch faulthandler for &apos;MismatchedFault&apos;"'/>
        </catch>
      </faulthandlers>
    </scope>
    <trace value='"after outer scope"'/>
  </sequence>
</process>
}

Nested Scopes, Outer Fault Handler Has Catch

Suppose you have the following BPL (partially shown):

Partial BPL diagram with nested scopes

The rest of this BPL is as follows:

Partial BPL diagram with the following elements in order: trace, catch, catchall, join, trace, and end

This BPL business process does the following:

  1. The first <trace> element generates the message before outer scope.

  2. The first <scope> element starts the outer scope.

  3. The next <trace> element generates the message in outer scope, before inner scope.

  4. The second <scope> element starts the inner scope.

  5. The next <trace> element generates the message in inner scope, before throw.

  6. The <throw> element throws a specific, named fault ("MyFault").

  7. Control now goes to the <faulthandlers> defined within the inner <scope>. A <catch> exists, but its fault value is "MismatchedFault". There is no <catchall> in the inner scope.

  8. Control goes to the <faulthandlers> block in the outer <scope>. It contains a <catch> whose fault value is "MyFault".

  9. The next <trace> element generates the message in outer scope catch faulthandler for 'MyFault'.

  10. The second <scope> ends.

  11. The last <trace> element generates the message after outer scope.

Event Log Entries

The corresponding Event Log entries look like this:

Event log with entries for inner and outer scope elements

XData for This BPL

This BPL is defined by the following XData block:

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 &apos;MismatchedFault&apos;"'/>
          </catch>
        </faulthandlers>
      </scope>
      <trace value='"in outer scope, after inner scope"'/>
      <faulthandlers>
        <catch fault='"MyFault"'>
          <trace value=
            '"In outer scope catch faulthandler for &apos;MyFault&apos;"'/>
        </catch>
      </faulthandlers>
    </scope>
    <trace value='"after outer scope"'/>
  </sequence>
</process>
}

Thrown Fault with Compensation Handler

In business process management, it is often necessary to reverse some segment of logic. This convention is known as “compensation.” The ruling principle is that if the business process does something, it must be able to undo it. That is, if a failure occurs, the business process must be able to compensate by undoing the action that failed. You need to be able to unroll all of the actions from that failure point back to the beginning, as if the problem action never occurred. BPL enables this with a mechanism called a compensation handler.

BPL <compensationhandler> blocks are somewhat like subroutines, but they do not provide a generalized subroutine mechanism. You can “call” them, but only from <faulthandler> blocks, and only within the same <scope> as the <compensationhandler> block. The <compensate> element invokes a <compensationhandler> block by specifying its name as a target. Extra quotes are not needed for this syntax:

<compensate target="general"/>

Compensation handlers are only useful if you can undo the actions already performed. For example, if you transfer money into the wrong account, you can transfer it back again, but there are some actions that cannot be neatly undone. You must plan compensation handlers accordingly, and also organize them according to how far you want to roll things back.

Suppose you have the following BPL:

Complex BPL diagram with compensationhandler element in scope element

This BPL business process does the following:

  1. The Context tab (not shown) defines a property called MyBalance and sets its value to 100.

  2. The first <trace> element generates the message before scope balance is, followed by the value of MyBalance.

  3. The <scope> element starts the scope.

  4. The next <trace> element generates the message before debit.

  5. The <assign> element decrements MyBalance by 1.

  6. The next <trace> element generates the message after debit.

  7. The <throw> element throws a specific, named fault ("BuyersRegret").

  8. Control now goes to the <faulthandlers>. A <catch> exists whose fault value is "BuyersRegret", so control goes there.

    If we drill down into this <catch> element, we see the following:

    BPL diagram with the following shapes in order: start, trace, trace, compensate, trace, end

  9. Within this <catch>, the first <trace> element generates the message in catch faulthandler for 'BuyersRegret'.

  10. Within this <catch>, the second <trace> element generates the message before restore balance is, followed by the current value of MyBalance.

  11. The <compensate> element is used. For this element, target is a <compensationhandler> whose name is RestoreBalance. Within this <compensationhandler> block:

    • A <trace> statement outputs the message “Restoring Balance”

    • An <assign> statement increments MyBalance by 1.

    Note:

    It is not possible to reverse the order of <compensationhandlers> and <faulthandlers>. If both blocks are provided, <compensationhandlers> must appear first and <faulthandlers> second.

  12. The next <trace> element generates the message after restore balance is, followed by the current value of MyBalance.

  13. The <scope> ends.

  14. The last <trace> element generates the message after scope balance is, followed by the current value of MyBalance.

Event Log Entries

The corresponding Event Log entries look like this:

Event log with several entries

XData for This BPL

This BPL is defined by the following XData block:

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 &apos;BuyersRegret&apos;"'/>
          <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>
}
FeedbackOpens in a new tab