Skip to content

Configuration

Stetson Robinson edited this page Apr 10, 2020 · 14 revisions

IMPORTANT: This Kogito wiki is deprecated. For the latest Kogito documentation, see the Kogito documentation page. To contribute to Kogito documentation, see the master-kogito branch of the kie-docs repository in GitHub.

Configuration of the runtime

There are several configuration that can be needed when implementing Kogito enabled applications. Some (but not all) are

  • registering work item handlers

  • registering event listeners

  • enabling metrics

  • enabling persistence

  • enabling events produced by runtimes

  • use Kogito Job Service as timer service

These various items might require dependencies setup, code and configuration in the application.properties file.

Registering work item handlers

To be able to use custom service tasks a work item handler must be registered. Once the work item handler is implemented to can be either packaged in the application itself or as dependency of the application.

WorkItemHandlerConfig class should be created to provide custom work item handlers. It must implement org.kie.kogito.process.WorkItemHandlerConfig although recommended is to always extend the default implementation (org.kie.kogito.process.impl.DefaultWorkItemHandlerConfig) to benefit from the out of the box provided handlers as well.

@ApplicationScoped
public class CustomWorkItemHandlerConfig extends DefaultWorkItemHandlerConfig {{
    register("MyServiceTask", new MyServiceWorkItemHandler());
}}
Note
These classes are meant to be injectable so ensure you properly annotate the class (@ApplicationScoped/@Component) so they can be found and registered.

You can also take advantage of life cycle method like @PostConstruct and @PreDestroy to manage your handlers.

Registering event listeners

Event listeners are registered in similar way as work item handlers. Though these are separated into rule or process related event listeners and as such are implementing different interfaces.

  • org.kie.kogito.process.ProcessEventListenerConfig

  • org.kie.kogito.rules.RuleEventListenerConfig

same as with work item handlers it’s recommended to always extend the default implementation of the config class

  • org.kie.kogito.process.impl.DefaultProcessEventListenerConfig

  • org.drools.core.config.DefaultRuleEventListenerConfig

@ApplicationScoped
public class ProcessEventListenerConfig extends DefaultProcessEventListenerConfig {

    public ProcessEventListenerConfig() {
        super(new CustomProcessEventListener());
    }
}
@ApplicationScoped
public class RuleEventListenerConfig extends DefaultRuleEventListenerConfig {

    public RuleEventListenerConfig() {
        super(new CustomRuleEventListener());
    }
}
Note
These classes are meant to be injectable so ensure you properly annotate the class (@ApplicationScoped/@Component) so they can be found and registered.

Enabling metrics

Kogito comes with base coverage for processes and rules evaluation. These can be directly exposed via HTTP endpoint. It is based on Prometheus and the content it serves is in that format as well so can be directly consumed by Prometheus server.

Add dependencies

Add the following dependency to your project pom.xml

<dependency>
  <groupId>org.kie.kogito</groupId>
  <artifactId>monitoring-prometheus-addon</artifactId>
  <version>${kogito.version}</version>
</dependency>

Register event listeners

Depending on capabilities of Kogito used in the service you might register either or both of the following listeners

  • org.kie.kogito.monitoring.process.PrometheusProcessEventListener

  • org.kie.kogito.monitoring.rule.PrometheusMetricsDroolsListener

To enable process related metrics create ProcessEventListenerConfig class or add the Prometheus listener (org.kie.addons.monitoring.process.PrometheusProcessEventListener) to already existing config class.

@ApplicationScoped
public class ProcessEventListenerConfig extends DefaultProcessEventListenerConfig {

    public ProcessEventListenerConfig() {
        super(new PrometheusProcessEventListener("acme-travels"));
    }
}

To enable rule related metrics create RuleEventListenerConfig class or add the Prometheus listener (org.kie.addons.monitoring.rule.PrometheusMetricsDroolsListener) to already existing config class.

@ApplicationScoped
public class RuleEventListenerConfig extends DefaultRuleEventListenerConfig {

    public RuleEventListenerConfig() {
        super(new PrometheusMetricsDroolsListener("acme-travels"));
    }
}
Note
There is single argument for both classes and that is identifier that describes the data coming from the runtimes. It can be used to group the metrics later on when visualising them.

Enabling persistence

See Persistence section to learn more about persistence and how to enable it.

Enable runtime events

Runtimes can produce events based on processed data. Currently this mainly applies to process execution but will most likely be expanded to cover also decisions and rules.

Process runtime events

Runtime engine can emit events based on the execution context of given request (aka unit of work). The main aim for these events is to notify 3rd parties about changes to the process instance and its data.

Process Instance Events

To avoid too many events being sent and to optimise both producer and consumer side there will be only one event per process instance emitted.

That event will consists of relevant information such as

  • process instance metadata e.g. process id, process instance id, process instance state, etc

  • node instances executed, list of all node instances that have been triggered/left during the execution

  • variables - current state of variables after the execution

These events will provide complete view over the process instances being executed without need to respond to individual events that can be consumed via ProcessEventListener.

Important
these events are produced only when the execution finished successfully, meaning without any errors during the course of execution.

In case there are multiple process instances executed within single request/unit of work each process instance will be given a dedicated event.

{
  "specversion": "0.3",
  "id": "f52af50c-4fe2-4581-9184-7ad48137fb3f",
  "source": null,
  "type": "ProcessInstanceEvent",
  "time": "2019-08-05T17:47:49.019494+02:00[Europe/Warsaw]",
  "data": {
    "id": "c1aced49-399b-4938-9071-b2ffa3fb7045",
    "parentInstanceId": null,
    "rootInstanceId": null,
    "processId": "deals",
    "processName": "SubmitDeal",
    "startDate": 1565020069015,
    "endDate": null,
    "state": 1,
    "nodeInstances": [
      {
        "id": "a8fe24c4-27a5-4869-85df-16e9f170f2c4",
        "nodeId": "2",
        "nodeDefinitionId": "CallActivity_1",
        "nodeName": "Call a deal",
        "nodeType": "SubProcessNode",
        "triggerTime": 1565020069015,
        "leaveTime": null
      },
      {
        "id": "7a3bf1b1-b167-4928-969d-20bddf16c87a",
        "nodeId": "1",
        "nodeDefinitionId": "StartEvent_1",
        "nodeName": "StartProcess",
        "nodeType": "StartNode",
        "triggerTime": 1565020069015,
        "leaveTime": 1565020069015
      }
    ],
    "variables": {
      "name": "my fancy deal",
      "traveller": {
        "firstName": "John",
        "lastName": "Doe",
        "email": "[email protected]",
        "nationality": "American",
        "address": {
          "street": "main street",
          "city": "Boston",
          "zipCode": "10005",
          "country": "US"
        }
      }
    }
  },
  "kogitoProcessinstanceId": "c1aced49-399b-4938-9071-b2ffa3fb7045",
  "kogitoParentProcessinstanceId": null,
  "kogitoRootProcessinstanceId": null,
  "kogitoProcessId": "deals",
  "kogitoProcessinstanceState": "1"
}

The event itself is in format of CloudEvent so can be easily consumed, it comes with few extensions to allow event routing based on the event metadata without looking into the body of the event

  • kogitoProcessinstanceId

  • kogitoParentProcessinstanceId

  • kogitoRootProcessinstanceId

  • kogitoProcessId

  • kogitoProcessinstanceState

  • type of the event is set to ProcessInstanceEvent

User Task Instance Events

In addition to process instance events, in case given execution (unit of work) makes any interactions with user tasks then additional event (one for each user task) will be produced.

That event will consists of relevant information such as

  • task metadata such as name, description, priority, start and complete dates

  • task input and output data

  • task assignments actual owner, potential users and groups, business admin and business admin groups, excluded users

  • task reference name that should be used to interact with the task via runtime service’s endpoints

{
  "data": {
    "adminGroups": [],
    "adminUsers": [],
    "excludedUsers": [],
    "id": "4d899471-19dd-485d-b7f4-b313185d430d",
    "inputs": {
      "Locale": "en-UK",
      "trip": {
        "begin": "2019-09-22T22:00:00Z[UTC]",
        "city": "Boston",
        "country": "US",
        "end": "2019-09-26T22:00:00Z[UTC]",
        "visaRequired": true
      },
      "TaskName": "VisaApplication",
      "NodeName": "Apply for visa",
      "Priority": "1",
      "Skippable": "true",
      "traveller": {
        "address": {
          "city": "Krakow",
          "country": "Poland",
          "street": "Polna",
          "zipCode": "12345"
        },
        "email": "[email protected]",
        "firstName": "Jan",
        "lastName": "Kowalski",
        "nationality": "Polish"
      }
    },
    "outputs": {},
    "potentialGroups": [],
    "potentialUsers": [],
    "processId": "travels",
    "processInstanceId": "63c297cb-f5ac-4e20-8254-02f37bd72b80",
    "referenceName": "VisaApplication",
    "startDate": "2019-09-16T15:22:26.658Z[UTC]",
    "state": "Ready",
    "taskName": "Apply for visa",
    "taskPriority": "1"
  },
  "id": "9c340cfa-c9b6-46f2-a048-e1114b077a7f",
  "kogitoProcessId": "travels",
  "kogitoProcessinstanceId": "63c297cb-f5ac-4e20-8254-02f37bd72b80",
  "kogitoUserTaskinstanceId": "4d899471-19dd-485d-b7f4-b313185d430d",
  "kogitoUserTaskinstanceState": "Ready",
  "source": "http://localhost:8080/travels",
  "specversion": "0.3",
  "time": "2019-09-16T17:22:26.662592+02:00[Europe/Berlin]",
  "type": "UserTaskInstanceEvent"
}

The event itself is in format of CloudEvent so can be easily consumed, it comes with few extensions to allow event routing based on the event metadata without looking into the body of the event

  • kogitoUserTaskinstanceId

  • kogitoUserTaskinstanceState

  • kogitoProcessinstanceId

  • kogitoProcessId

  • type of the event is set to UserTaskInstanceEvent

Publishing events

Events by default are only emitted when there is at least one publisher configured. There might be many event publishers that can be used to send/publish these events into different channels etc.

By default there are message based event publishers shipped with Kogito

  • Reactive message based that allows to send events to Kafka, AMQP, MQTT, Camel and this is used for Quarkus based runtimes

  • Spring Kafka based that allows to send events to Kafka and is dedicated to runtimes based on Spring Boot

Additional event producers can be developed by implementing org.kie.kogito.event.EventPublisher that needs to be annotated with respective annotations for bean discovery.

Configure event publisher for Quarkus based runtime

Install and configure Apache Kafka

Install Apache Kafka in the preferred way and create new topics named

  • kogito-processinstances-events

  • kogito-usertaskinstances-events

Add dependency

Add following into the pom.xml of the application.

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-smallrye-reactive-messaging-kafka</artifactId>
</dependency>
<dependency>
  <groupId>org.kie.kogito</groupId>
  <artifactId>kogito-events-reactive-messaging-addon</artifactId>
  <version>${kogito.version}</version>
</dependency>

Configure messaging channel

Edit application.properties file located under src/main/resources and add following entries

mp.messaging.outgoing.kogito-processinstances-events.connector=smallrye-kafka
mp.messaging.outgoing.kogito-processinstances-events.topic=kogito-processinstances-events
mp.messaging.outgoing.kogito-processinstances-events.value.serializer=org.apache.kafka.common.serialization.StringSerializer

mp.messaging.outgoing.kogito-usertaskinstances-events.connector=smallrye-kafka
mp.messaging.outgoing.kogito-usertaskinstances-events.topic=kogito-usertaskinstances-events
mp.messaging.outgoing.kogito-usertaskinstances-events.value.serializer=org.apache.kafka.common.serialization.StringSerializer

Start the application and on each request (that actually modifies the state of a process instance) you should see new messages to show up on the kogito-processinstances-events topic. In addition, whenever there are user tasks interactions new messages should show up on 'kogito-usertaskinstances-events' topic.

Under heavy load for producer there might be error thrown in case the back pressure is overloaded. Use following property to disable waiting for completion which should make the overall throughput higher

mp.messaging.outgoing.kogito-processinstances-events.waitForWriteCompletion=false
mp.messaging.outgoing.kogito-usertaskinstances-events.waitForWriteCompletion=false

Configure event publisher for SprintBoot based runtime

Install and configure Apache Kafka

Install Apache Kafka in the preferred way and create new topics named

  • kogito-processinstances-events

  • kogito-usertaskinstances-events

Add dependency

Add following into the pom.xml of the application.

<dependency>
  <groupId>org.springframework.kafka</groupId>
  <artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
  <groupId>org.kie.kogito</groupId>
  <artifactId>kogito-events-spring-boot-addon</artifactId>
  <version>${kogito.version}</version>
</dependency>

Configure messaging channel

Edit application.properties file located under src/main/resources and add following entries

kafka.bootstrapAddress=localhost:9092
@Configuration
public class KafkaProducerConfig {

    @Value(value = "${kafka.bootstrapAddress}")
    private String bootstrapAddress;


    @Bean
    public ProducerFactory<String, String> producerFactory() {
        Map<String, Object> configProps = new HashMap<>();
        configProps.put(JsonSerializer.ADD_TYPE_INFO_HEADERS, false);
        configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
        configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        return new DefaultKafkaProducerFactory<>(configProps);
    }

    @Bean
    public KafkaTemplate<String, String> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }

}

Start the application and on each request (that actually modifies the state of a process instance) you should see new messages to show up on the kogito-processinstances-events topic.

Control event publishing

There are several application properties that allow to control the event publishing

  • kogito.events.processinstances.enabled - allows to enable/disable publishing process instance events, defaults to true

  • kogito.events.usertasks.enabled - allows to enable/disable publishing user task instance events, defaults to true

Use Kogito Job Service as timer service

By default Kogito services use in memory timer service to to handle time based events defined in the process. This does not cover long time intervals and is only suitable for short delays defined in the process. To allow for more advanced use cases where the time intervals can be of days or weeks or when there is extra handling required such as retries, Kogito Job Service can be used.

See details about Kogito Job Service here.

To enable Kogito Job Service to be used as timer service there are two steps required

  1. Add dependency that is specific to the runtime your service is using (Quarkus or Spring Boot)

  2. Configure locations of the Kogito Job Service and Callback

Kogito Job service for Quarkus

Add following dependency to your pom.xml

<dependency>
  <groupId>org.kie.kogito</groupId>
  <artifactId>jobs-management-quarkus-addon</artifactId>
</dependency>

Kogito Job service for Spring Boot

Add following dependency to your pom.xml

<dependency>
  <groupId>org.kie.kogito</groupId>
  <artifactId>jobs-management-springboot-addon</artifactId>
</dependency>

Configure service

Add following properties to application.properties file to inform the Kogito Job Service add-on about locations of both Job Service itself and callback to be used when timer expires.

kogito.jobs-service.url=http://localhost:8085
kogito.service.url=http://localhost:8080
Note
Before this can be used, make sure that Kogito Job Service is started and the configuration given above is valid for its location.

Configuring rest clients used by job service add-on

In case default settings of the rest clients used by the job service add-on are not sufficient, custom configured clients can be provided by the service implementors.

The top of rest client will differ depending on the runtime used

  • quarkus - uses Vert.x web client io.vertx.ext.web.client.WebClient

  • spring boot - uses RestTemplate org.springframework.web.client.RestTemplate

in both cases just product an instance of the above client to allow fine grained setup of the client.