Share via


Windows Workflow Foundation: Rules Driven Workflows In Coffee Ordering

By Zoiner Tejada, Hershey Technologies

Articles in this series

Published: September, 2009

Summary: Most business processes   include a sequence of decisions that are made in a particular order. Here we are focusing on the sequencing of rules wherein choices made later in the process may put into question or even invalidate previous outcomes and as such requires those previous decisions (and those that follow it) to be re-evaluated. For example, in the case of a promotion, an increase in salary past a certain threshold triggers the need to re-evaluate allocations of stock, vacation days, etc., that were computed previously. In this article we explore the notion of workflows built using business rules that are interdependent-- where the evaluation of one rule can set off a cascade of re-evaluations of previously executed rules.

Introducing the Scenario

The scenario we explore, while simple, captures the subtlety of rules driven workflows which have a need for recursive rule evaluation. In this scenario we examine the business process of helping a customer decide upon the right bag of coffee beans given both the customers stated requirements and the availability of matching product. Consider that our coffee merchant allows customers to choose a coffee bean type, a size, and whether or not the beans are decaffeinated.  The options offered are as follows:

Options

Coffee Bean Type

Arabian Mocha, Sumatra, Italian or Any (to indicate no preference)

Size

8 oz, 12 oz, 16 oz bags

Decaf

Yes or No

Effectively, if the customer elects the “any” option for the coffee bean type, they are allowing the merchant to choose for them given their choice of bag size and caffeinated/decaffeinated preference. The suggestion of coffee bean type always starts with Arabian Mocha, then Sumatra and then Italian until a match is found for all stated requirements. Behind the scenes, the merchant might have certain rules that describe the inventory that is available for a customer to order from:

Rules

Arabian Mocha is only available in the 16 oz size.

Sumatra is not available in decaf.

Italian is not available in the 8 oz size.

Taking a look at the combination of options and business rules leads to some interesting insights which our rules driven workflow will have to incorporate.  The simplest of these are those orders whose static requirements cannot be met (such as an order for a 12 oz bag of Arabian Mocha or a decaf Sumatra).  From there additional insights result as the business rules start to work together-- when the customer allows for any coffee bean type.  For example, if a customer requests a 12 oz decaffeinated bag, the system should recommend Italian based on the order of suggestion and rules previously established. Walking through how the system evaluates this logic will help us understand the implementation using Windows Workflow Foundation:

  • Customer Request - Coffee Bean Type: Any, Size: 12oz, Decaf: Yes
    • System tries to suggest Arabian Mocha first, but cannot because Arabian Mocha is not available in the 12 oz size.
    • The system next tries to suggest Sumatra, which is available in the 12 oz size, but is not available in decaf.
    • Finally, the system suggests Italian which is available in the 12 oz size and in decaf.
    • Since this matches all of the customer’s requirements the system chooses this as the suggestion to the customer and stops rule evaluation.

Notice how in the above, we began by suggesting a coffee bean type, then for that type evaluated the size option and if successful the decaf option. Failing to match either the size or the decaf option forced us to suggest another coffee bean type and re-evaluate the size and decaf options for the active coffee bean type.

The last interesting insight to incorporate is to handle the case where a customer’s requirements simply cannot be met, and no suggestion can be made. This is the case, for example, when the customer requests an 8 oz decaf bag.

Using the Policy Activity

The aforementioned rules can be encapsulated in a single activity offered by WF that provides the rule re-evaluation behavior we need in order to make a proper suggestion: the Policy Activity.

Figure 1: Policy Activity

The PolicyActivity relies on a collection of rules in a structure known as a RuleSet. These RuleSets are defined at the scope of the workflow and can be re-used across multiple policy activities by configuring the PolicyActivity’s RuleSetReference property. The figure below shows the RuleSet we have defined in this workflow. Additional RuleSets defined in the workflow would also be listed here.

Figure 2: Defining Rules

As one would expect the RuleSet consists of an individual rules- the editor for which is brought up either by double clicking the PolicyActivity or from the Select Rule Set dialogue, selecting a Rule Set and clicking Edit. The following shows Rule Set Editor with all of the rules for the coffee policy configured:

Figure 3: Full Ruleset

We will explore the features of the rule sets, rules and how the editor helps us configure them as we examine each rule. Our initial rule “InitialSuggestion” handles the case when the customer has requested a coffee type of “any” and we need to initialize our suggestion. The workflow hosting our PolicyActivity has a property called Selection of type CoffeeSelection which looks as follows:

    [Serializable]
    public class CoffeeSelection
    {
        public string CoffeeType { get; set; }
        public int SizeOz { get; set; }
        public bool IsDecaf { get; set; }
        public string SuggestedType { get; set; }
        public string Error { get; set;}
    }

When the workflow is launched, the customer’s values (for CoffeeType, SizeOz, and IsDecaf) are captured from the user interface.

Figure 4: User Interface

Individual rules are structured into Condition, Then Action and Else Action. For our “InitialSuggestion” we have it configured so that if the customer selected the “any” coffee bean type then we will initialize our SuggestType value from a helper method in the coffee inventory service (a simple static class that simply suggests coffee bean types in order Arabian Mocha, Sumatra and then Italian).  This is expressed in Actions box. Otherwise, our SuggestedType must use what the customer requested, so we initialize our SuggestedType as such in the Else Actions box. The Reevaluation of this rule has been set to Never to enforce that this initialization should take place at most once, regardless of how many times the rule set might be re-evaluated by using full-chaining (described later) . The Priority of 1000 ensures this is the first rule evaluated in the rule set (higher priorities are evaluated first , with ties broken by alphabetic order of the rule name).

Our next rule “NoSuggestions” handles the case where the customer selected “any” for the CoffeeType, but no suggestion could be made.

Figure 5: "No Suggestions" Rule

This is where we first see some rule set re-evaluation behavior. Notice the Then Actions sets the error text and then has the keyword Halt. This means that if we reach this action, then after completing the actions described in the Then Actions box, the Rule Set should stop evaluating  rules (and effectively that the PolicyActivity is finished).

Next we have two rules that check the size option for the suggested coffee bean type. The only difference between CheckSize1 and CheckSize2 is whether the customer originally chose a coffee bean type of “any” and thereby allows the RuleSet to make suggestions upon failing to match by size or to halt further rule set evaluation because the requirements cannot be met.

Figure 6: CheckSize1 Rule

Figure 7: CheckSize2 Rule

Both actions make use of the CoffeeInventoryService which provides an IsInvalidSize method that encapsulates the size options described previously.

Finally, CheckDecaf1 and CheckDecaf2 perform a similar test against the IsDecaf option, making use of another helper method called IsNotAvailableInDecaf that returns true when the coffee bean type indicated does not have a decaffeinated variant.

Figure 8: CheckDecaf1 Rule

Figure 9: CheckDecaf2 Rule

After the execution of this Policy Activity, the Selection variable in the workflow will have the SuggestedType set with a null Error, or a non-null SuggestedType and an Error if no suggestions could be made. For example, a successful suggestion might look as follows:

Figure 10: Successful Suggestion

Whereas a situation in which a suggestion could not be made would result in:

Figure 11: No Suggestion

The re-evaluation behavior of a Rule Set is configured globally by the Chaining option (found in the top right corner of the Rule Set Editor dialogue). The options are Sequential (meaning no re-evaluation occurs), Explicit Update Only (meaning that Then Actions or Else Actions must include the special Update keyword when re-evaluation should occur) or Full Chaining (where the rules engine causes revaluation of a rule when it determines a value relied upon by a condition of that rule is changed by another action). In our scenario we take advantage of Full Chaining.

Let us return to the example we gave earlier where a customer requested a 12 oz, decaf bean of any type and see how the Rule Set’s evaluation behavior executes (starting from when the PolicyActivity first executes):

Rule Set Pass # Customer Request - Coffee Bean Type: Any, Size: 12oz, Decaf: Yes Rule Execution Behavior within the Rule Set

1.

System tries to suggest Arabian Mocha first, but cannot because Arabian Mocha is not available in the 12 oz size.

  1. Executes the Condition for Initial Suggestion. Because the customer requested “any” as the bean type (thereby matching the Condition), the inventory service suggests “arabian mocha” as the first coffee bean type to try against the customer’s other requirements (the Then action).The Initial Suggestion rule has now run for the first and only time as its Reevaluation property is set to Never.
  2. Executes the Condition on the No Suggestions Rule and takes the no-op Else action because the system was able to make a suggestion.
  3. Executes the Condition on the CheckSize1 rule, and takes the no-op Else action because the customer did not specify a specific bean type.
  4. Executes the Condition on the CheckSize2 rule, which returns true as 12 oz is an invalid size for the system suggested Arabian Mocha. Therefore the Then action is executed which queries the Inventory Service for the next suggested type- “Sumatra”.

2

The system next tries to suggest Sumatra, which is available in the 12 oz size, but is not available in decaf.

  1. The setting of SuggestedType triggers re-evaluation of the rules in the rule set (in order of priority and alpha sort) whose condition looks at the value of SuggestedType.
  2. Initial Suggestion is skipped because it is set to never revaluate its condition, and it has already executed once.
  3. Executes the Condition on the No Suggestions Rule and takes the no-op Else action because the system was able to make a suggestion.
  4. Executes the Condition on the CheckSize1 rule, and takes the no-op Else action because the customer did not specify a specific bean type.
  5. Executes the Condition on the CheckSize2 rule and takes the no-op Else action because the Inventory System indicates that 12 oz is a valid size for “sumatra”.
  6. Executes the Condition on the CheckDecaf1 rule, and takes the no-op Else action because the customer did not specify a specific bean type.
  7. Executes the Condition on the CheckDecaf2 rule, which returns true as the Inventory Service indicates that “sumatra” is not available in decaf. The Then action is executed which sets the SuggestedType property to the next coffee bean type available in the list- “Italian”.

3

Finally, the system suggests Italian which is available in the 12 oz size and in decaf.

  1. The setting of SuggestedType triggers re-evaluation of the rules in the rule set whose condition looks at the value of SuggestedType.
  2. Initial Suggestion is skipped because it is set to never revaluate its condition, and it has already executed once.
  3. Executes the Condition on the No Suggestions Rule and takes the no-op Else action because the system was able to make a suggestion.
  4. Executes the Condition on the CheckSize1 rule, and takes the no-op Else action because the customer did not specify a specific bean type.
  5. Executes the Condition on the CheckSize2 rule and takes the no-op Else action because the Inventory System indicates that 12 oz is a valid size for “italian”.
  6. Executes the Condition on the CheckDecaf1 rule, and takes the no-op Else action because the customer did not specify a specific bean type.
  7. Executes the Condition on the CheckDecaf2 rule, and takes the no-op Else action because the Inventory System indicates that “italian” is available in decaf.

Since this matches all of the customer’s requirements the system chooses this as the suggestion to the customer and stops rule evaluation.

The Rule Set has completed execution of its rules and the Policy Activity completes.

It is also worth exploring the case where Rule Set evaluation is halted because the requirements cannot be satisfied. Assume the request was for an 8 oz decaf of any coffee bean type. The rule set would evaluate similarly through the third pass in the previous table up until step 7, where the Inventory System would indicate that “italian” is not available in decaf. Therefore, the Inventory System would be queried for a Suggested Type and it would return “unavailable”. This would trigger a 4th pass across the rules set. Initial Suggestion is skipped as before. The Condition for No Suggestions returns true, so the Then Action of No Suggestions is executed which sets an error messages and then stops any further rule set re-evaluation with an explicit Halt.  At this point the Policy Activity completes.

Comparing State Machine and Sequential Implementations

Given that all of the logic was expressed in a single PolicyActivity, the two implementations are trivial and the difference minimal. In sequential form, the workflow looks as follows:

Figure 12: Implementing the Workflow as a Sequential Workflow

As a State Machine, it takes on the following form:

Figure 13: Implementing the Workflow as a State Machine

Where the evalSuggestionPolicy StateIntializationActivity contains the PolicyActivity:

Figure 14: evalSuggestionPolicy State