In a previous article I discussed the parallel execution of activities in BPEL, more specifically in Oracle BPEL PM 11g (TP4). This article concluded that true parallellism hardly exists. The branches within a Flow get their chance in turns to execute their next step. Not until an activity is complete in one branch can the next branch take over and make one step. The only exception I was able to determine was the Receive activity that waits for an Asynchronous Service to call in with its results – when a branch is executing the Receive (waiting!), other branches can continue with their next step. It seemed that normal Wait operations and Synchronous calls (with nonBlockingInvoke set) should also free the lock the current branch has and allow others to run, but I could not observe that behavior in Technical Preview 4.
I hinted in that article that we can take more control over the way the activities in the parallel branches are executed. Right now it seems that when a Flow executes, the BPEL PM determines when which branch gets a chance to run, whereby it seems – though I do not know whether that is guaranteed behavior – that the branches (BPEL sequence activities) get a turn in the order in which they are defined in the BPEL process and one activity at a time. In this article we discuss the <link> element that gives us a little more control over when an activity is ready to run. It allows us to define dependencies between activities in different branches in the Flow.
Let’s take an example. A simple process that contains a single Flow with three branches. Each branch has two Assign steps. Each step adds its own identifier to a global String. After the process completes, this string is returned to the invoker. It should contain the identifier of each Assign step. The order of these identifiers in the result tell us the order in which the steps were executed.
The process looks like this:
Running it results in the following:
When we look at the audit trail, we get confirmed what the result string also tells us: the C branch was executed first, next the B and then the A branch after which the branches got their turn again for the second activity to execute:
Let’s now take some control over this process. Let’s say that we do not want C2 to start before A2 has run. We can do that using the LINK element in our BPEL Process.
We add the link definition to the Flow:
<flow name="Flow_1"> <links> <link name="A2Completes"/> </links> <sequence name="Sequence_A">
What we specify here is that inside the Flow we can refer to a Link. A Link is almost like an ‘ activity completed event’ that consumers can subscribe to. In our case we will subscribe Assign step C2 to this link (event). We also have to indicate which activity triggers the link – produces the event if you will. In the activity that triggers this link – that by its very completion makes the link complete – we include a source element (as that activity is the source for the (completion of the) link:
<assign name="Assign_A2"> <source linkName="A2Completes"/> <copy> ....
In the activity that depends on the link, that should hold its breath and not start running until the link is complete, we add a target element:
<assign name="Assign_C2"> <target linkName="A2Completes"/> <copy> ...
This means: Assign_C2 can only start when the link called A2Completes is satisfied. And that happens when the activity on which the source has been defined completes. Note that a link can be target for multiple activities. Also note that an activity can have multiple targets. An activity can also have multiple sources. However, a link can only have a single source.
With this link in place, let’s redeploy and run the service again:
Here we have it: C2 is now the last activity to run, because of its dependency on A2. Strangely enough is now C1 also moved to almost the end of the process. That is not required and is probably specific to the way Oracle BPEL PM deals with the link.
The visual process flow looks the same, obviously.
More complexity: a new link and several WAIT steps
Let’s add another link, this time called C2Completes, triggered by the completion of C2. Make B2 depend on that link:
<assign name="Assign_B2"> <target linkName="C2Completes"/>
We also add two WAIT steps in the process:
We have stated that C2 waits for A2 to complete and B2 has to wait for C2. Which is somewhat unfortunate as the B branch is the only one without explicit WAIT activities. Yet it is now set up to be the last to complete.
The result confirms our expectation – as well as the fact that Oracle BPEL PM implements the BPEL spec – B2 executes after C2 has completed and C2 starts only when A2 is done. The order of A1, B1 and C1 is not specified.
The audit trail:
The <link> element provides us with more control over the order of steps within a Flow construct. We can determine dependencies between activities in different branches, which can be quite useful.
In a later article we can look at Transition Conditions and Join Conditions. These give us even more refined control, allowing us to specified that an activity can only start when a previous activity (link source) has completed with a certain result.