So far, we’ve looked at some relatively simple packages, in terms of their flow. In this post, we’re going to look at how to handle more complex control flow in Biml.
One feature of Biml is the ConstraintMode property that’s part of packages and containers. This property controls how precedence constraints are generated in the control flow. In the simple case, if you want all tasks to be run in sequence, you can set the ConstraintMode to Linear. This causes the package to be produced with all tasks connected sequentially by Success precedence constraints, in the order they were specified in the Biml. So, the following Biml:
<Biml xmlns="http://schemas.varigence.com/biml.xsd"> <Packages> <Package Name="Control Flow Sample 1" AutoCreateConfigurationsType="None" ConstraintMode="Linear"> <Tasks> <Dataflow Name="Task 1"/> <Dataflow Name="Task 2"/> <Dataflow Name="Task 3"/> </Tasks> </Package> </Packages> </Biml>
results in a package that looks like this:
This type of linear flow is great in some situations, but sometimes you need more control. In those cases, you can change the ConstraintMode to Parallel. The generated package will not have any automatically created precedence constraints, so it will look like this:
Once a container is in Parallel constraint mode, you can start adding explicit precedence constraints. Let’s use an example to highlight this. Imagine you have a package that needs to run three data flows. (I’m using data flows for the example because they are simple to read in Biml, and I want the focus to be on the constraints, not the tasks.) I want one data flow to execute first – this data flow will be named “Me First”. If “Me First” succeeds, the data flow named “Me Next (Success)” should execute. The third data flow, named “I’m Last (Always)” should always be executed, regardless of the success or failure of the other two tasks. So my package should look like this:
So how do we get this output from Biml? We can use the PrecedenceConstraints collection on each task. At it’s simplest, you just add an Input to the collection, and reference the output of the task that should execute prior to this one. In Biml, all tasks have a built-in output named Output. You can reference it using TaskName.Output (“Me First.Output” in the example below). This will create a regular, Success constraint between the tasks.
<Dataflow Name="Me Next (Success)"> <PrecedenceConstraints> <Inputs> <Input OutputPathName="Me First.Output"/> </Inputs> </PrecedenceConstraints> </Dataflow>
For the next set of constraints, we want to use the OR logical type, using the LogicalType property, for the constraints, since either of them should cause the third task to run. We also need to explicitly set the evaluation value on these, using the EvaluationValue property.
<Dataflow Name="I'm Last (Always)"> <PrecedenceConstraints LogicalType="Or"> <Inputs> <Input OutputPathName="Me First.Output" EvaluationValue="Failure"/> <Input OutputPathName="Me Next (Success).Output" EvaluationValue="Completion"/> </Inputs> </PrecedenceConstraints> </Dataflow>
You can also add expression constraints to the Inputs, to control whether tasks run based on the results on an expression. You use the EvaluationOperation and Expression properties to configure that.
<Package Name="Control Flow Sample 3" AutoCreateConfigurationsType="None" ConstraintMode="Parallel"> <Variables> <Variable Name="Continue" DataType="Int32">0</Variable> </Variables> <Tasks> <Dataflow Name="Task 1"/> <Dataflow Name="Task 2"> <PrecedenceConstraints> <Inputs> <Input OutputPathName="Task 1.Output" EvaluationOperation="Expression" Expression="@Continue==1"/> </Inputs> </PrecedenceConstraints> </Dataflow> </Tasks> </Package>
That Biml results in a package that looks like this.
That’s how to control the precedence constraints. I’ve uploaded the Biml from this post to my SkyDrive here, so you can download and experiment with this yourself. In the next post, we’ll look at controlling the data paths in a data flow.