Invoking sub-processes
There are two methods available to invoke a sub-process—the embedded sub-process and the reusable sub-process. The embedded sub-process also contains a special case called the multi-instance embedded sub-process, which as the name suggests, allows us to run multiple instances of the embedded sub-process. Let us take a look at the differences and when we might use each.
Embedded sub-processes
An embedded sub-process is included in the same process model as its parent process. It is, in fact, included in the flow of the parent process. The embedded sub-process can be expanded to show its contents, or collapsed, in which case it is shown as a single task in the parent process as we can see in the following diagram:
Embedded sub-processes provide a number of capabilities that make them useful:
They establish scope for conversations, variables, and exceptions. This means that we can define a conversation or a variable inside an embedded sub-process and it will only be visible inside that embedded sub-process. This is particularly useful if we need to deal with a large amount of data for a short time during the process. By placing that data in variables that are scoped (defined) inside an embedded sub-process, we will only force the runtime environment to persist them while the embedded sub-process is running, thereby improving performance and minimizing our storage needs.
They also set the boundary for exceptions. We can attach boundary events to an embedded sub-process (these will be discussed in detail in Chapter 4, Handling Exceptions) so that we can localize the exception handling for anything that goes wrong during the embedded sub-process. This can be useful if we want to be able to catch an error and then retry the logic inside the embedded sub-process. In this case, you can think of the embedded sub-process as being similar to the
try/catch
structure in many common programming language environments.Embedded sub-processes can see and manipulate their parent's variables, unlike reusable sub-processes.
Embedded sub-processes can be placed inside each other to create hierarchies of scopes, each with their own variables, conversations, and exception handling if desired.
They provide a mechanism to loop or repeat. You can specify an arbitrary number of times to repeat, or you can use an expression to calculate how many times to repeat the embedded sub-process. These expressions are able to reference variables and can also use XPath functions. You can evaluate the expression before or after the loop execution, giving you the equivalent of
do...while
andwhile
semantics. You can also set a maximum number of iterations to prevent infinite loops.They also provide a mechanism that iterates over a collection, which is discussed in the next section.
Multi-instance embedded sub-processes
The multi-instance embedded sub-process is a special case that allows you to iterate over a collection of data. This will be covered in detail in Chapter 3, Working with Arrays, but for now let's discuss the main characteristics of the multi-instance embedded sub-process:
The multiple instances can be run sequentially (one after the other) or in parallel.
You can specify how many instances to run at runtime based on the cardinality of an object (like an array) or by iterating over a collection . Loops based on cardinality resemble a
for
loop, while those based on a collection resemble aforeach
loop.You can additionally specify a completion condition so that you are able to "short circuit" the iteration if you find that you are finished before all of the iterations are complete. This may be the case, for example, when you are searching for a single item in the collection that you want to do something to or with. Once you find that item, it is no longer necessary to continue iterating over the rest of the collection.
Multi-instance embedded sub-processes also share the characteristics of "normal" embedded sub-processes. They establish scope for conversations, variables, and exception handling, can be placed inside each other, and can access their parent's variables.
An interesting case to consider is iteration over lists of lists. Using a multi-instance embedded sub-process you can iterate over the items in the outer list in parallel, while a second multi-instance embedded sub-process iterates over the items in the inner list, which is the current element of the outer list sequentially.
Note
A good example of when this might happen is performing pathology tests. Often a series of tests can be performed one after the other on a single sample, but other tests require different samples. If there were n
series of tests to be performed, this could be represented as a list of lists and modeled in this fashion.
This is illustrated in the following process model, which also includes a final review and possible repeating of one or more series of tests:
Reusable sub-processes
Reusable sub-processes are included in the same project as their parent process(es), but in a separate process model. They must start with a catch none event and end with a throw none event.
Any process in the same project (composite) as the reusable sub-process is able to call the reusable sub-process, however, they are not exposed as services, they are not shown in composite, and there is no way to invoke them directly from outside of the composite in which they are defined. Additionally, at runtime a reusable sub-process is shown as executing inline, within the outer process flow—the process that invoked it—even though it was modeled in a separate process model.
Reusable sub-processes are invoked using the call activity. Variables of the parent (calling) process are not available to the reusable sub-process unless you pass them to the reusable sub-process as arguments .
Recommended sub-process style to use
The following table is a quick guide to which kind of sub-process you should use in various circumstances.
Embedded |
Multi-instance |
Reusable | |
---|---|---|---|
Want access to parent's variables |
Yes |
Yes |
Must pass them |
Need looping |
Yes |
No |
No* |
Need to iterate over a collection |
No |
Yes |
No* |
Need to call it from more than one parent |
No |
No |
Yes |
Want parallel execution |
No |
Yes |
No* |
Want to establish a new scope |
Yes |
Yes |
Yes |
Want short-circuit completion |
No |
Yes |
No* |
Note
The scenarios marked with asterisks in the preceding table can be achieved using a reusable sub-process, but you must do a bit more of the work yourself if you choose that approach—you will need to explicitly model things such as looping into your parent process.