11 min read

Business processes specified using BPEL will interact with their partners through operation invocations of web services. Web services are based on loosely coupled Service Oriented Architecture (SOA) . The communication between web services is done over Internet connections that may or may not be highly reliable. Web services could also raise faults due to logical errors and execution errors arising from defects in the infrastructure. Therefore, BPEL business processes will need to handle faults appropriately. BPEL processes may also need to signal faults themselves. Fault handling and signaling is an important aspect of business processes designed using BPEL.

Faults in BPEL can arise in various situations:

  • When a BPEL process invokes a synchronous web service operation, the operation might return a WSDL fault message, which results in a BPEL fault.
  • A BPEL process can explicitly signal (throw) a fault.
  • A fault can be thrown automatically, for example, when a join failure has occurred.
  • The BPEL server might encounter error conditions in the runtime environment, network communications, or any other such area. BPEL defines several standard faults.

WSDL faults

WSDL faults occur due to synchronous operation invocations on partner web services. In WSDL, such faults are denoted with the &ltfault> element within the &ltoperation> declaration. In BPEL, WSDL faults are identified by the qualified name of the fault and the target namespace of the corresponding port type used in the operation declaration.

The TravelApproval operation used on the TravelApprovalPT port type with input and output messages is shown in the following WSDL excerpt:

<portType name=”TravelApprovalPT”>
<operation name=”TravelApproval”>
<input message=”tns:TravelRequestMessage” />
<output message=”aln:TravelResponseMessage” />
</operation>
</portType>


To add fault information to the operation, we first need to define a corresponding message. For simplicity, this message will be of the xs:string type:

<message name=”TravelFaultMessage”>
<part name=”error” type=”xs:string” />
</message>


Now we will add the fault declaration to the operation signature shown previously:

<portType name=”TravelApprovalPT”>
<operation name=”TravelApproval”>
<input message=”tns:TravelRequestMessage” />
<output message=”aln:TravelResponseMessage” />
<fault name=”fault” message=”tns:TravelFaultMessage” />
</operation>
</portType>


WSDL does not require that we use unique fault names within the namespace used to define the operation. This implies that faults that have the same name and are defined within the same namespace will be considered as the same fault in BPEL. Keep this in mind when designing services that can potentially become partners of BPEL business processes, because this can lead to conflicts in fault handling during execution.

Signaling faults

A business process may sometimes need to explicitly signal a fault. For such a situation, BPEL provides the &ltthrow> activity. It has the following syntax:

<throw faultName=”name” />


BPEL does not require that we define fault names in advance, prior to their use in the &ltthrow> activity. This flexible approach can also be error-prone, because there is no compile-time checking of fault names. Therefore, a typo could result in a situation where a misspelled fault might not be handled by the designated fault handler. Faults can also have an associated variable that usually contains data related to the fault. If such a variable is associated with the fault, we need to specify it when throwing the fault. This is done by using the optional faultVariable attribute as shown here:

<throw faultName=”name” faultVariable=”variable-name” />


The following example shows the most straightforward use of the &ltthrow> activity; where a WrongEmployeeName fault is thrown, no variable is needed. Remember that fault names are not declared in advance:

<throw faultName=”WrongEmployeeName” />


The faults raised with the &ltthrow> activity have to be handled in the BPEL process. Faults that are not handled will not be automatically propagated to the client as is the case in modern programming languages (Java for example). Rather, the BPEL process will terminate abnormally. Sometimes, however, we may want to signal faults to clients.

Signaling faults to clients in synchronous replies

A BPEL process offers operations to its clients through the &ltreceive> activity. If the process wants to provide a synchronous request/response operation, it sends a &ltreply> activity in response to the initial &ltreceive>. Remember that the type of the operation is defined in the WSDL document of the BPEL process. A synchronous request/response operation is defined as an operation that has an input and an output message, and an optional fault message.

If such an operation has the fault part specified, we can use the &ltreply> activity to return a fault instead of the output message. The syntax of the &ltreply> activity in this case is:

<reply partnerLink=”partner-link-name”
portType=”port-type-name”
operation=”operation-name”
variable=”variable-name” <!– optional –>
faultName=”fault-name” >
</reply>


When we specify a fault name to be returned through the &ltreply> activity, the variable name is optional. If we specify a variable name, then the variable has to be of the fault message type as defined in WSDL.

Example

Let’s modify the BPEL process definition in the synchronous travel example and signal the fault (TravelFaultMessage) to the client by using the &ltreply> activity.

First, we need to declare an additional variable that will hold the fault description to return to the client. The variable is of the TravelFaultMessage type:

<variables>
<!– fault to the BPEL client –>
<variable name=”TravelFault” messageType=”trv:TravelFaultMessage”/>
</variables>


Then we return the fault to the BPEL process client. We will need to check if something went wrong in the travel process. For the purpose of this example, we will check whether the selected flight ticket has been approved. This information is stored in the confirmationData part of the TravelResponse variable in the Approved element. Note that this is an oversimplification, but it demonstrates how to return faults. We can use an &ltif> activity to determine whether the ticket is approved; then we construct the fault variable and use the &ltreply> activity to return it to the client. This is shown in the following code:

<!– Check if the ticket is approved –>
<if>
<condition>
$TravelResponse.confirmationData/aln:Approved=’true’
</condition>
<!– Send a response to the client –>
<reply partnerLink=”client”
portType=”trv:TravelApprovalPT”
operation=”TravelApproval”
variable=”TravelResponse”/>
<else>
<sequence>
<!– Create the TravelFault variable with fault description –>
<assign>
<copy>
<from>string(‘Ticket not approved’)</from>
<to variable=”TravelFault” part=”error” />
</copy>
</assign>
<!– Send a fault to the client –>
<reply partnerLink=”client”
portType=”trv:TravelApprovalPT”
operation=”TravelApproval”
variable=”TravelFault”
faultName=”fault” />
</sequence>
</else>
</if>


If the ticket is not approved, the following fault is signaled to the client:

<TravelFault>
<part name=”error”>
<error >
Ticket not approved
</error>
</part>
</TravelFault>


We have seen that signaling faults in synchronous replies is easy. Let us now discuss signaling faults in asynchronous scenarios.

Signaling faults to clients in asynchronous scenarios

If an asynchronous BPEL process needs to notify the client about a fault, it cannot use the &ltreply> activity. Remember that in asynchronous scenarios the client does not wait for the reply; rather, the process uses a callback. To return a fault in callback scenarios, we usually define additional callback operations on the same port type. Through these callback operations, we can signal that an exceptional situation has prevented normal completion of the process.

To demonstrate how faults can be propagated to the client using a callback operation, we will use the asynchronous travel process example. First, we need to modify the travel BPEL process WSDL and introduce another operation called ClientCallbackFault. This operation consists of an input message called tns:TravelFaultMessage. The message is of the string type. The declaration of the operation and the message is shown in the following code excerpt:

<message name=”TravelFaultMessage”>
<part name=”error” type=”xs:string” />
</message>
<portType name=”ClientCallbackPT”>
<operation name=”ClientCallback”>
<input message=”aln:TravelResponseMessage” />
</operation>
<operation name=”ClientCallbackFault”>
<input message=”tns:TravelFaultMessage” />
</operation>
</portType>


We can use the &ltif> activity to determine whether the ticket has been approved. If the ticket is not approved, however, we &ltinvoke> the ClientCallbackFault operation instead of using the &ltreply> activity to signal the fault to the client. This is shown in the following code excerpt:

<!– Check if the ticket is approved –>
<if>
<condition>
$TravelResponse.confirmationData/aln:Approved=’true’
</condition>
<!– Make a callback to the client –>
<invoke partnerLink=”client”
portType=”trv:ClientCallbackPT”
operation=”ClientCallback”
inputVariable=”TravelResponse” />
<else>
<sequence>
<!– Create the TravelFault variable with fault description –>
<assign>
<copy>
<from>string(‘Ticket not approved’)</from>
<to variable=”TravelFault” part=”error” />
</copy>
</assign>
<!– Send a fault to the client –>
<invoke partnerLink=”client”
portType=”trv:ClientCallbackPT”
operation=”ClientCallbackFault”
inputVariable=”TravelFault” />
</sequence>
</else>
</if>


In the next section, we will look at how to handle faults thrown in BPEL processes.

Handling faults

Now that we are familiar with how faults are signaled, let us consider how the business process handles faults. When a fault occurs within a business process (this can be a WSDL fault, a fault thrown by the BPEL process, or any other type of fault), it means that the process may not complete successfully. The process can complete successfully only if the fault is handled within a scope.

Business processes handle faults through fault handlers.

A business process can handle a fault through one or more fault handlers. Within a fault handler, the business process defines custom activities that are used to recover from the fault and recover the partial (unsuccessful) work of the activity in which the fault has occurred.

The fault handlers are specified before the first activity of the BPEL process, after the partner links and variables. The overall structure is shown in the following code excerpt:

<process …>
<partnerLinks>

</partnerLinks>
<variables>

</variables>
<faultHandlers>
<catch … >
<!– Perform an activity –>
</catch>
<catch … >
<!– Perform an activity –>
</catch>

<catchAll>
<!– catchAll is optional –>
<!– Perform an activity –>
</catchAll>
</faultHandlers>
<sequence>
</sequence>
</process>


We can see that within the fault handlers, we specify several &ltcatch> activities where we indicate the fault that we would like to catch and handle. Within a fault handler, we have to specify at least one &ltcatch> or a &ltcatchAll> activity. Of course, the &ltcatchAll> activity can be specified only once within a fault handler.

Usually we will specify several &ltcatch> activities to handle specific faults and use the &ltcatchAll> to handle all other faults. The &ltcatch> activity has two attributes, of which we have to specify at least one:

  • faultName: Specifies the name of the fault to be handled.
  • faultVariable: Specifies the variable type used for fault data. Additionally, we can specify one of the following attributes (both are optional, but we may specify one, not both):
      • faultMessageType: Specifies the WSDL message type of the fault to be handled.

    faultElement: Specifies the XML element type of the fault to be handled.

The flexibility of &ltcatch> activities is high and several variations are permissible. Listed ahead are the most common:

<faultHandlers>
<catch faultName=”trv:TicketNotApproved” >
<!– First fault handler –>
<!– Perform an activity –>
</catch>
<catch faultName=”trv:TicketNotApproved”
faultVariable=”TravelFault” >
<!– Second fault handler –>
<!– Perform an activity –>
</catch>
<catch faultVariable=”TravelFault” >
<!– Third fault handler –>
<!– Perform an activity –>
</catch>
<catchAll>
<!– Perform an activity –>
</catchAll>
</faultHandlers>


We can see that fault handlers in BPEL are very similar to try/catch clauses found in modern programming languages.

LEAVE A REPLY

Please enter your comment!
Please enter your name here