Skip to content

Commit

Permalink
docs: on demand rulesets take validity range into account (#2458)
Browse files Browse the repository at this point in the history
## Proposed change

## Related issues

<!-- * 🐛 Fix #issue -->
<!-- * 🐛 Fix resolves #issue -->
<!-- * 🚀 Feature #issue -->
<!-- * 🚀 Feature resolves #issue -->
* :octocat: Pull Request #2400
  • Loading branch information
vscaiceanu-1a authored Nov 13, 2024
2 parents 6453a3a + c262820 commit b431c3d
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 28 deletions.
37 changes: 20 additions & 17 deletions docs/rules-engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This document describes the various concepts and models that are part of the [Ot
It serves as an introduction course before you can integrate it within your application following the
[rules engine implementation guide](./how-to-use/README.md).

As covered in the [package documentation](https://www.npmjs.com/package/@o3r/rules-engine), the rules engine is a
As covered in the [package documentation](https://www.npmjs.com/package/@o3r/rules-engine), the rules engine is a
client-based mechanism that evaluates a list of [Rulesets](#ruleset) to define [actions](#action) to apply based on the
application's context.

Expand All @@ -17,8 +17,11 @@ application's context.
The `Ruleset` object exposes a sorted list of rules to process one after the other.

It may include optional conditions to enable or disable the whole Ruleset based on simple triggers such as:
- `validityRange`: whether the date of execution of the Ruleset is part of the date range of execution
- `linkedComponents`: whether specific components are part of the page (see [linked components](./how-to-use/dedicated-component-ruleset.md))
- `validityRange`: whether the date of execution of the Ruleset is part of the date range of execution
- `linkedComponents`: whether specific components are part of the page (see [linked components](./how-to-use/dedicated-component-ruleset.md))

The two conditions work together: if a ruleset has both `validityRange` and `linkedComponents` the ruleset
will not be executed if the component is part of the page but the date is outside the validity range.

If any of the rules belonging to the same ruleset fails due to an error, none of the resulting actions from any of these
rules will be executed as they may be deeply linked.
Expand All @@ -27,16 +30,16 @@ Rulesets are described by the [ruleset schema](https://github.com/AmadeusITGroup

### Rule

A `Rule` contains a set of conditions that outputs a list of [actions](#action) after processing.
A `Rule` contains a set of conditions that outputs a list of [actions](#action) after processing.

These conditions and actions are referred to as blocks and follow a tree architecture:
These conditions and actions are referred to as blocks and follow a tree architecture:
a block can be an `IfElseBlock` (branch of the tree) or an `ActionBlock` (leaf of the tree).

The `IfElseBlock` contains conditions to meet as well as the blocks to execute depending on the success or failure of
the condition.
The `IfElseBlock` contains conditions to meet as well as the blocks to execute depending on the success or failure of
the condition.
The conditions can be linked via `AND` and `OR` expressions.

An `IfElseBlock` can result in another `IfElseBlock` or an `ActionBlock`.
An `IfElseBlock` can result in another `IfElseBlock` or an `ActionBlock`.

This allows for nested conditions as demonstrated by the [nested condition Ruleset example](./examples/nested-conditions.md).

Expand All @@ -61,8 +64,8 @@ Each condition in an `IfElseBlock` can contain up to three different parts:
The operator is a method that will evaluate whether a condition is met. It can take up to two operands.

While the Otter framework already provides a set of operators ready for use, it is also possible to use your own operator
that will fit your needs. You can check on the [custom operator documentation](./how-to-use/custom-operator.md) as well
as the [ruleset generation documentation](./how-to-use/industrialize-ruleset-generation.md) if you want to generate metadata
that will fit your needs. You can check on the [custom operator documentation](./how-to-use/custom-operator.md) as well
as the [ruleset generation documentation](./how-to-use/industrialize-ruleset-generation.md) if you want to generate metadata
for your own operators.

The exhaustive list of exposed operators is available in the `rules.operators.metadata.json`.
Expand All @@ -82,13 +85,13 @@ which is why it is only available in the npm artifact.
### Action

The ActionBlock defines the action to be executed.
The ActionBlock defines the action to be executed.
Each Action is identified by a unique ID, specifying the process to trigger and any associated payload.

The Otter framework provides a few built-in actions linked to Otter-specific features:
* `UPDATE_CONFIG` modifies the configuration of a configurable component
(provided by [@o3r/configuration](https://www.npmjs.com/package/@o3r/configuration))
* `UPDATE_ASSET` overrides the path of an asset which uses the `o3rDynamicContent` pipe
* `UPDATE_ASSET` overrides the path of an asset which uses the `o3rDynamicContent` pipe
(provided by [@o3r/dynamic-content](https://www.npmjs.com/package/@o3r/dynamic-content))
* `UPDATE_LOCALISATION` substitutes the translation of a key with the one from another key.
([@o3r/localization](https://www.npmjs.com/package/@o3r/localization))
Expand All @@ -113,14 +116,14 @@ This allows a big optimization since the rules engine will react to a fact chang
of rules that relies on this fact.

Facts can be defined inside the code of the application, as described in the [custom fact documentation](./how-to-use/custom-fact.md),
or can be defined by the ruleset itself.
or can be defined by the ruleset itself.

In that case, we call it a [runtime fact](#runtime-fact).

> [!WARNING]
> A rule depending on a fact will be re-evaluated whenever this fact is updated.
> A rule depending on a fact will be re-evaluated whenever this fact is updated.
> If you use a fact that will be updated a lot in a short time frame, you may encounter performance issues.
>
>
> You can avoid this by:
> * disabling the ruleset if the component impacted by the rule is missing from the page (see [linkedComponents](./how-to-use/dedicated-component-ruleset.md))
> * avoiding timer facts with a high frequency (1s for example)
Expand All @@ -129,13 +132,13 @@ In that case, we call it a [runtime fact](#runtime-fact).

A runtime fact is a temporary fact that is only available in the Ruleset it is used in. It can be the result of a rule
`SET_FACT` action providing it has been declared in the rule `outputRuntimeFacts`.
The runtime fact can then be used as an input for another rule condition provided it has been declared in the rule's
The runtime fact can then be used as an input for another rule condition provided it has been declared in the rule's
`inputRuntimeFacts`.

You can follow the [runtime-facts](./examples/runtime-facts.md) example to help you use it in your Ruleset.

> [!WARNING]
> The runtime fact is only accessible in the Ruleset where it has been defined. If you create two runtime facts in
> The runtime fact is only accessible in the Ruleset where it has been defined. If you create two runtime facts in
> two different Rulesets, they will be two different entities isolated from each other.
> The runtime fact's value is reset between two executions of the Ruleset.
Expand Down
22 changes: 11 additions & 11 deletions docs/rules-engine/how-to-use/dedicated-component-ruleset.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Rules engine - Dedicated ruleset for component

The goal of the feature is to create a ruleset that will be executed if and only if it's used. This will improve the performances
The goal of the feature is to create a ruleset that will be executed if and only if it's used. This will improve the performances
of your application as the rules engine will not be triggered if the facts are updated but your rule has no effect
at the moment -- for instance if it is supposed to change the configuration of a missing component.

Expand All @@ -12,7 +12,7 @@ ruleset they are linked to. This is done in their `ngOnInit` and `ngOnDestroy` m
You can make a component `linkedComponents` compatible thanks the following Otter CLI command:
`ng g rules-engine-to-component --path=[path-to-my-component-file]`

This command will compute the component's identifier and add the methods to enable or disable the ruleset
This command will compute the component's identifier and add the methods to enable or disable the ruleset
matching the component name.

```diff
Expand All @@ -30,7 +30,7 @@ import {ChangeDetectionStrategy, Component, ViewEncapsulation, inject, OnInit, O
})
- export class MyComponent {
+ export class MyComponent implements OnInit, OnDestroy {

+ private readonly rulesEngineService = inject(RulesEngineRunnerService, { optional: true });
+ private readonly componentIdentifier = computeItemIdentifier('MyComponent', '@scope/components');

Expand All @@ -48,12 +48,12 @@ import {ChangeDetectionStrategy, Component, ViewEncapsulation, inject, OnInit, O
```

> [!IMPORTANT]
> If you are managing your ruleset with a dedicated UI, please note that your component should either be a Page,
> a Block or an ExposedComponent for it to appear in the component metadata file which will make it visible in your UI.
> If you are managing your ruleset with a dedicated UI, please note that your component should either be a Page,
> a Block or an ExposedComponent for it to appear in the component metadata file which will make it visible in your UI.
## How to link a ruleset to a component

Now that your component can trigger or prevent the run of a ruleset, you can set the `linkedComponents` property to
Now that your component can trigger or prevent the run of a ruleset, you can set the `linkedComponents` property to
prevent the execution of the Ruleset until your component is available in the page:

```json5
Expand All @@ -71,7 +71,7 @@ prevent the execution of the Ruleset until your component is available in the pa
// 'or' keyword means: if at least one component from the list is registered, the ruleset is active
// 'and' keyword is not supported, but you can request it via a new issue (https://github.com/AmadeusITGroup/otter/issues/new?assignees=&labels=enhancement&projects=&template=5-FEATURE-FORM.yaml&title=%5BFeature%5D%3A+),
// and we will add the support
"or": [
"or": [
{
"library": "@scope/components",
"name": "MyComponent"
Expand All @@ -90,19 +90,19 @@ prevent the execution of the Ruleset until your component is available in the pa
}
```
> [!INFO]
> In v10 and the previous version, the Otter framework exposed the `linkedComponent` property to activate a ruleset on demand.
> In v10 and the previous version, the Otter framework exposed the `linkedComponent` property to activate a ruleset on demand.
> This is now deprecated and will be removed in v12. Use `linkedComponents` instead.
## How it works

`RulesEngineRunnerService` handles the subscriptions for all the rulesets.
At the initialization of the application, the service listens to a selector to get all the active rulesets that are not linked
to any components and that met the validity date range criteria (described in the `validityRange` property of the ruleset).
Then it will merge the result with the on-demand rulesets -- the rulesets with `linkedComponents` currently activated.
Then it will merge the result with the on-demand rulesets -- the rulesets with `linkedComponents` currently activated and that also respect the `validityRange`.

As soon as the component is instantiated on the page, i.e. when `ngOnInit` is called, it will add its ID to the
As soon as the component is instantiated on the page, i.e. when `ngOnInit` is called, it will add its ID to the
list of requested linked rulesets.
`RulesEngineRunnerService` will then add the relevant rulesets in its on-demand list, which will trigger their evaluation.

Once a component is removed from the list of requested rulesets, i.e. that is when `ngOnDestroy` is called, and if
Once a component is removed from the list of requested rulesets, i.e. that is when `ngOnDestroy` is called, and if
none of the other components in the page are linked to the ruleset, it will revert to its previous 'disabled' mode.

0 comments on commit b431c3d

Please sign in to comment.