In 2021 it’s almost undeniable that modern application development needs to target the cloud, given the requirements of flexibility, scalability and availability imposed by today’s world.
Event-driven architectures have proven to be well suited models for this purpose. As a result, we’re adopting these principles in several components of Kogito, which aims to be the next generation cloud-native business automation solution.
This blogpost presents a new component that aligns with this view: the event-driven decisions addon. It is available since Kogito v1.2.
Key concepts
This addon enables the evaluation of decision models in an event-driven fashion, so that it can be used as part of an event processing pipeline.
It comes in two flavours: Quarkus and Spring Boot.
The developer only needs to include the correct version as dependency of his Kogito app and configure the input/output topics. The wiring is done by the Kogito code-generation and framework specific dependency injection.
The execution is triggered upon receiving an event containing the initial context from a specific Kafka input topic. The result is then sent to a Kafka output topic (which may be the same). Both input and output events are formatted as CloudEvents.
Its capabilities are implemented to be similar to the ones available via REST endpoints:
- trigger evaluation of the whole model or of a specific decision service
- receive only the context or the full DMN result in the output event
- filter out the inputs from the output context, no matter if returned alone or inside the DMN result
Event structure
Input event
A model evaluation is triggered by a specific event called DecisionRequest
. Here is the list of the supported fields, including the optional ones:
Field | Purpose | Mandatory | Default |
---|---|---|---|
data | Input context | yes | – |
id | CloudEvent ID | yes | – |
kogitodmnevaldecision | Name of decision service to evaluate. If specified the engine triggers the evaluation of this service only. | no | null |
kogitodmnfilteredctx | Boolean flag to enable/disable filtering out inputs from the context | no | false |
kogitodmnfullresult | Boolean flag to enable/disable receiving full DMN result as output | no | false |
kogitodmnmodelname | Name of DMN model to evaluate | yes | – |
kogitodmnmodelnamespace | Namespace of DMN model to evaluate | yes | – |
source | CloudEvent source | yes | – |
specversion | Must be equal to 1.0 as mandated by CloudEvent specification | yes | – |
subject | If specified, the engine will put the same value as subject of the output event. Its usage is up to the caller (e.g. as correlation ID). | no | null |
type | Must be equal to DecisionRequest | yes | – |
Example of DecisionRequest event
{
"specversion": "1.0",
"id": "a89b61a2-5644-487a-8a86-144855c5dce8",
"source": "SomeEventSource",
"type": "DecisionRequest",
"kogitodmnmodelname": "Traffic Violation",
"Kogitodmnmodelnamespace": "https://github.com/kiegroup/drools/kie-dmn/_A4BCA8B8-CF08-433F-93B2-A2598F19ECFF",
"data": {
"Driver": {
"Age": 25,
"Points": 13
},
"Violation": {
"Type": "speed",
"Actual Speed": 115,
"Speed Limit": 100
}
}
}
Output events
If the request is evaluated successfully, the system returns two different types of output events depending on the value of the kogitodmnfullresult
flag:
DecisionResponse
if only the output context is returnedDecisionResponseFull
if the full DMN result is returned
The results are always in the data field.
Example of DecisionResponse event
{
"specversion": "1.0",
"id": "d54ace84-6788-46b6-a359-b308f8b21778",
"source": "Traffic+Violation",
"type": "DecisionResponse",
"kogitodmnmodelnamespace": "https://github.com/kiegroup/drools/kie-dmn/_A4BCA8B8-CF08-433F-93B2-A2598F19ECFF",
"kogitodmnmodelname": "Traffic Violation",
"data": {
"Violation": {
"Type": "speed",
"Speed Limit": 100,
"Actual Speed": 115
},
"calculateTotalPoints": "function calculateTotalPoints( driver, fine )",
"Driver": {
"Points": 13,
"Age": 25
},
"Fine": {
"Points": 3,
"Amount": 500
},
"Should the driver be suspended?": "No"
}
}
Example of DecisionResponseFull event
{
"specversion": "1.0",
"id": "a18c409d-ab1f-4d6b-abc7-97327df8585f",
"source": "Traffic+Violation",
"type": "DecisionResponseFull",
"kogitodmnmodelnamespace": "https://github.com/kiegroup/drools/kie-dmn/_A4BCA8B8-CF08-433F-93B2-A2598F19ECFF",
"kogitodmnmodelname": "Traffic Violation",
"data": {
"namespace": "https://github.com/kiegroup/drools/kie-dmn/_A4BCA8B8-CF08-433F-93B2-A2598F19ECFF",
"modelName": "Traffic Violation",
"dmnContext": {
"Violation": {
"Type": "speed",
"Speed Limit": 100,
"Actual Speed": 115
},
"calculateTotalPoints": "function calculateTotalPoints( driver, fine )",
"Driver": {
"Points": 13,
"Age": 25
},
"Fine": {
"Points": 3,
"Amount": 500
},
"Should the driver be suspended?": "No"
},
"messages": [],
"decisionResults": [
{
"decisionId": "_4055D956-1C47-479C-B3F4-BAEB61F1C929",
"decisionName": "Fine",
"result": {
"Points": 3,
"Amount": 500
},
"messages": [],
"evaluationStatus": "SUCCEEDED"
},
{
"decisionId": "_8A408366-D8E9-4626-ABF3-5F69AA01F880",
"decisionName": "Should the driver be suspended?",
"result": "No",
"messages": [],
"evaluationStatus": "SUCCEEDED"
}
]
}
}
Error events
If, for some reason, the request event is malformed or contains wrong information so that the evaluation can’t be triggered, a DecisionResponseError
is sent as output.
In this case the data
field contains a string that specifies the error type:
Error Type | Meaning |
---|---|
BAD_REQUEST | Malformed input event (e.g. when some mandatory fields are missing) |
MODEL_NOT_FOUND | The specified model can’t be found in the current service |
Examples
The Kogito Examples repository contains two examples, one for Quarkus and one for Spring Boot, that you can use as a starting point to practice with this addon.
They also contain tests for every possible variation in the structure of the input/output events supported by the addon.
Conclusion
If you liked this article and are interested in the evolution of Kogito, stay tuned for more news!
Thanks for reading.