Fluent Commerce Logo
Docs
Sign In
Essential knowledge

Author:

Fluent Commerce

Changed on:

30 June 2024

Overview

The 

`run`
 method is called by the Workflow Engine when executing each Rule in a Ruleset triggered by an Orchestration Event.

Key points

  • Rules are the smallest building block for logic, it is important to remember that this method should be implemented to perform 1 simple task
  • You may not need all of these steps within your Rule. Some rules produce an action without a condition. Some rules do not need to query additional data. Make sure your Rule is as lean as possible, and simple to read.
  • The Rubix Plugin SDK provides a useful Util class to facilitate validation: RuleUtils
  • You can retrieve the data by using Context / Entity
  • Typically, a Rule will produce an output action.

Since Rules are the smallest building block for logic, it is important to remember that this method should be implemented to perform 1 simple task. Rarely should your Rule code ever be more than a few lines of code.

Rules are meant to be composable, and this means they should be self-contained, and not depend on any other Rule.

The 

`run`
 method receives a 
`Context`
 instance, which provides all the necessary contextual inputs to the Rule, as well as access to the Fluent API Client, and the Workflow Engine ActionFactory.

Rules are singletons, meaning the same single instance of the Rule is processing multiple threads. To this point, make sure you do not declare any runtime-specific values in the Rule Class properties, as these will not be threadsafe.

To implement the Rule, the following steps are usually followed within the 

`run`
 method:

  • Validation - validate the incoming parameters and event attributes are present
  • Retrieve additional Data - if the data required to evaluate or perform the Rule Action is not already available on the Context Entity or Event, retrieve it as efficiently as possible.
  • Conditional Logic - if the Rule Action is dependent on an evaluation, implement the simple conditional logic
  • Build the resulting Action - build the Action data
  • Produce the Action - call the 
    `context.action()`
     ActionFactory to produce the Action

You may not need all of these steps within your Rule. Some rules produce an action without a condition. Some rules do not need to query additional data. Make sure your Rule is as lean as possible, and simple to read.

A good practice for writing Rules where the resulting action is conditional, or where validations fail, is to exit early. This means avoiding difficult-to-read nested if statements. The logic should be as simple as possible. If there are too many conditions or evaluations in the Rule, it is likely too big and complex, and needs to be broken down into smaller building blocks for the composition of the logic in the Workflow.

Remember, your Rule should be reusable, and should be possible to position it one or more times in a Ruleset and Workflow.

To learn more about how to write well-crafted Rules, see Rule Coding Best Practices.

Validation

This stage typically involves validating all the required inputs to the Rule are both present, and valid. For example, if you have declared a number of Parameters or Event Attributes for use within the Rule logic, you should validate these first.

The Rubix Plugin SDK provides a useful Util class to facilitate validation: 

`RuleUtils`

For example, this snippet validates that the Order Id parameter exists:

1// imports & Rule Info annotation...
2@ParamInteger(name = "MyInt", description = "An Integer value for the Rule")
3public class MyCustomRule implements Rule {
4
5    // local fields...
6
7    public void run(C context) {
8
9        // Validation:
10        RuleUtils.validateRuleProps(context, "MyInt");
11
12        // continuing logic...
13
14    }
15}

Language: java

Name: Example

Description:

[Warning: empty required content area]

If any required validation fails, your Rule should exit immediately. To do this, you have 2 options:

  • Use a 
    `return`
     statement to immediately exist the Rule but continue processing the Ruleset.
  • Throw an Exception, and stop processing the Ruleset.

The choice of option is dependant on the behaviour you are expecting when this Rule's validation has failed.

For some Rules, this would indicate a critical error, which for others, it might simply indicate not to continue the logic and behaviour of the existing rule, but simply continue executing the following rules in the Ruleset.

Only you can determine the appropriate behaviour for your rule. The SDK 

`RuleUtils`
 has a mix of both boolean response and thrown exceptions.

Retrieving Data

Once you've completed the Validation phase, you may wish to retrieve any additional data you may need to execute your Rule logic.

The 

`Context`
 does already contain an Entity (
`context.getEntity()`
), however, this is a subset of the Entity itself.

It only contains the primary information (the common generic fields) of an Orchestrateable Entity:

  • EntityType - e.g: ORDER, FULFILMENT, etc.
  • EntityId
  • EntityRef
  • Type - e.g: HD, CC, etc.
  • Status
  • WorkflowInfo - e.g: the type and version of the application workflow.

Should you require more data from the specific Entity itself, you will need to perform a query using the GraphQL API Client available on the 

`Context`
.

For example, if you are writing a rule that needs to operate on a field or attribute of the Event Entity, you can retrieve this via a GraphQL query.

1// imports & Rule Info annotation...
2@ParamInteger(name = "MyInt", description = "An Integer value for the Rule")
3public class MyCustomRule implements Rule {
4
5    // local fields...
6
7    public void run(C context) {
8
9        // ...preceding logic
10
11        // Retrieve Data:
12        String orderId = context.getEntity().getId();
13
14        GetOrderByIdQuery query = GetOrderByIdQuery.builder().id(orderId).build();
15        GetOrderByIdQuery.Data data = (GetOrderByIdQuery.Data) context.api().query(query);
16
17        RuleUtils.validateQueryResult(context, data, this.getClass());
18
19        // continuing logic...
20
21    }
22}

Language: java

Name: Example

Description:

[Warning: empty required content area]

To learn more, see Working with GraphQL.

Conditional Logic

The next stage within the 

`run`
 method is to perform any conditional logic required prior to building and producing an action.

Let's say that for example, you only wished to continue the action of this rule if the 

`totalPrice`
 of the Order is greater than a 
`threshold`
 parameter with a value of $100.

1// imports & annotations...
2public class MyCustomRule implements Rule {
3
4    // local fields...
5
6    public void run(C context) {
7
8        // preceding logic...
9
10        // Simple Logic:
11        if (data.orderById().totalPrice() <= threshold) {
12            return;
13        }
14
15        // continuing logic...
16
17    }
18}

Language: java

Name: Example

Description:

[Warning: empty required content area]

Build the Action

Typically, a Rule will produce an output action. See Rule Actions here.

Some typical examples of output actions include:

  • Mutation - e.g: To update or save some new or changed data to the backend via a GraphQL API Mutation.
  • SendEvent - e.g: To send an event to trigger another workflow.
  • SendWebhook - e.g: To send an even to an external system.

In each of these cases, the data to be included in the action will need to be prepared.

1// imports & annotations...
2public class MyCustomRule implements Rule {
3
4    public void run(C context) {
5
6        // preceding logic...
7
8        // Prepare for Action:
9        AddAttributeToOrderMutation addAttributeToOrderMutation = AddAttributeToOrderMutation.builder()
10                .orderId(orderId)
11                .attributeName(IS_HIGH_VALUE_ORDER_ATTRIBUTE_NAME)
12                .attributeType(Attribute.Type.BOOLEAN.getValueClass().getSimpleName().toUpperCase())
13                .attributeValue(Boolean.TRUE)
14                .build();
15
16        // continuing logic...
17
18    }
19}

Language: java

Name: Example

Description:

[Warning: empty required content area]

To learn more, see Working with GraphQL.

Produce the Action

The final stage of the 

`run`
 method is to produce the output action.

1// imports & annotations...
2public class MyCustomRule implements Rule {
3
4    // local fields...
5
6    public void run(C context) {
7
8        // preceding logic...
9
10        // Produce Action:
11        context.action().mutation(addAttributeToOrderMutation);
12
13    }
14}

Language: java

Name: Example

Description:

[Warning: empty required content area]
Fluent Commerce

Fluent Commerce

Copyright © 2024 Fluent Retail Pty Ltd (trading as Fluent Commerce). All rights reserved. No materials on this docs.fluentcommerce.com site may be used in any way and/or for any purpose without prior written authorisation from Fluent Commerce. Current customers and partners shall use these materials strictly in accordance with the terms and conditions of their written agreements with Fluent Commerce or its affiliates.

Fluent Logo