The different implementations available

The RuntimeManager and RuntimeEngine are interfaces that can be implemented in any way a specific domain requires. There is no correct way of using the runtime managers, because the specifics of what your organization is trying to accomplish will determine whether a KIE session should be shared between different processes or not. Nevertheless, the jBPM6 project provides a number of implementations for the most common situations.

Depending on which implementation of the runtime manager we use, we will need to request a RuntimeEngine instance with different parameters. The runtime manager provides the getRuntimeEngine method to obtain a RuntimeEngine instance using a Context object as a parameter. This Context object will have the responsibility of identifying the actual instance of the KIE session and other configuration components for our runtime that we need for each different context.

The following implementations of the RuntimeManager interface are already provided in jBPM6:

  • Singleton Runtime Manager
  • Per Process Instance Runtime Manager
  • Per Request Runtime Manager

We will discuss each one in detail, learn how they can be used, and see the different types of Context objects that should be used to obtain the RuntimeEngine instances from each one of them.

Singleton Runtime Manager

The Singleton Runtime Manager makes sure a single KIE Session is used for all interactions with the runtime engine, as shown in the following diagram:

Singleton Runtime Manager

The jBPM6 code base provides a factory method to create a Singleton Runtime Manager. A code section from the singleton-runtime-manager project for this chapter where this factory method is being used is shown here:

RuntimeManager manager = RuntimeManagerFactory.
        Factory.get().
        newSingletonRuntimeManager(
                runtimeEnvironment, "node-identifier");

As you can see, it receives two parameters. The second one is optional, and it identifies a runtime manager uniquely. Given that runtime managers should behave as singletons, the factory keeps a register of all runtime managers until they're closed to make sure that you cannot instantiate the same runtime manager twice.

The get factory method mentioned before will instantiate a SingletonRuntimeManager object. This object stores a file with the KIE session ID that should be used. Every time a new instance of SingletonRuntimeManager is created, it checks if that file is already created. This session ID is later on retrieved from the database, or if persistence is not being used, from an in-memory HashMap.

Each time a runtime engine is created, a reference to a TaskService instance is also created. Since the TaskService instance acts as a stateless service with only the persistence keeping state information, no distinction is made between the different built-in runtime managers when it comes to creating the Human task component.

The Singleton Runtime Manager will require a context parameter to retrieve the RuntimeEngine instance. Since there is no distinction required between different environments (because they all share the same KIE session), we can use an EmptyContext instance or null parameters to retrieve the runtime engine:

RuntimeEngine engine = manager.getRuntimeEngine(
        EmptyContext.get());

With SingletonRuntimeManager, every RuntimeEngine instance returned will have the same KIE session object. This has its own advantages and disadvantages.

On the one hand, all processes that will be running on the same session can interact with each other through the rule engine memory, and feed combined rule executions with data. This allows you to have many processes interacting with each other as well as with rules, letting the processes remain simple enough, and complex decisions being handled by rules. Also, it allows for performance monitoring rules to be written and executed on the same environment as the processes are running.

On the other hand, having rules sharing information between different process instances can also lead to complications, particularly if we want to write rules that take into account only the objects of a specific process instance in a Business Rule task. Also, when persistence and concurrent invocations of process instances are being used, all of them will be derived form the same session that will have to execute them one at a time. This could lead to performance degradation.

The CDI injection

The jBPM6 project provides CDI annotations to directly inject a SingletonRuntimeManager instance in your managed beans. To distinguish it from other types of runtime managers, you should mark it with both the @javax.inject.Inject annotation and the @org.kie.internal.runtime.manager.cdi.qualifier.Singleton annotation. That way, the CDI initialization will know to inject a singleton runtime manager instance without having to declare its specific type. It can mark a RuntimeEnvironment instance as well:

@Inject @Singleton
RuntimeManager manager;
@Inject @Singleton
RuntimeEnvironment environment;

Remember that CDI is called upon initialization, so always inject the manager but not the RuntimeEngine instance.

Per Request Runtime Manager

The Per Request Runtime Manager does the opposite of the singleton instance; it creates a new KIE session the first time a request is made in a particular thread. Each runtime engine returned from the manager will have a new KIE session for the duration of the thread, as the following diagram depicts:

Per Request Runtime Manager

The jBPM6 code base provides a factory method to create a Per Request Runtime Manager. A code section from the per-request-runtime-manager project for this chapter where that factory method is being used is shown here:

RuntimeManager manager = RuntimeManagerFactory.
        Factory.get().
        newPerRequestRuntimeManager(
                runtimeEnvironment, "node-identifier");

As you can see, it receives two parameters. The second one is optional, and it identifies a runtime manager uniquely, in the same way as we explained for the Singleton Runtime Manager.

The get factory method instantiates a PerRequestRuntimeManager object. This object will keep a ThreadLocal reference pointing to the KIE session in one particular thread. If it is a nonpersistent environment, the reference will be lost the moment the runtime engine is disposed of. This doesn't make much sense unless you run fully-synchronous, automatic processes that will be completed the moment they return from the startProcess method invocation, or in a single code block.

However, if you are in a persistent environment, all references to long-lived process instances will be kept in the database, as well as any process instance reference that is waiting for a specific signal. In these cases, the Per Request Runtime Manager provides the most isolation regarding execution of processes and rules. All rules will be fired with only the data that is present in the process instance or explicitly added to the working memory before calling a process related invocation in the KIE session.

The Per Request Runtime Manager will require a context parameter to retrieve the RuntimeEngine instance associated to a specific process instance ID. However, in the same way as the Singleton Runtime Manager, it will not condition the KIE Session to be used (in this case, it will always be a new one), so we can use the EmptyContext instance:

RuntimeEngine engine = manager.getRuntimeEngine(EmptyContext.get());
ProcessInstance pInst = engine.getKieSession().startProcess("procId");
Long procInstId = pInst.getId();
manager.disposeRuntimeEngine(engine);

The PerRequestRuntimeManager injection provides enough isolation of processes to guarantee the highest scalability possible, but the rules associated with the process execution cannot take advantage of gathering cross-process instance information. Information that could be used in cross referencing complex events fired by different process instances will not be available, because every time a new KIE session is created, the working memory is initialized from scratch.

The CDI injection

The jBPM6 project provides CDI annotations for the PerRequestRuntimeManager injection in managed beans. To distinguish it from other types of runtime managers, you should mark it with both the @javax.inject.Inject annotation and the @org.kie.internal.runtime.manager.cdi.qualifier.PerRequest annotation. CDI initialization will inject a runtime manager instance per request without having to declare its specific type. It can mark a RuntimeEnvironment instance as well:

@Inject @PerRequest
RuntimeManager manager;
@Inject @PerRequest
RuntimeEnvironment environment;

Remember that CDI is called upon initialization, so always inject the manager but not the RuntimeEngine instance.

Tip

If you use a Per Process Instance or Per Request Runtime Manager, never inject KIE sessions or Human task service objects as CDI beans. They will be managed by the runtime manager and different KIE session instances and services could be created. Instead, you should only inject the manager and request sessions and services from a specific runtime engine.

Per Process Instance Runtime Manager

The Per Process Instance Runtime Manager takes care of registering the specific KIE session where a process was created. Each runtime engine returned from the manager will later on use the same session that created a specific process instance, as shown in the following diagram:

Per Process Instance Runtime Manager

The jBPM6 code base provides a factory method to create a Per Process Instance Runtime Manager. A code section from the per-process-instance-runtime-manager project for this chapter where this factory method is being used is shown here:

RuntimeManager manager = RuntimeManagerFactory.
        Factory.get().
        newPerProcessInstanceRuntimeManager(
                runtimeEnvironment, "node-identifier");

As you can see, it receives two parameters. The second one is optional, and identifies a runtime manager uniquely, in the same way as we explained for the Singleton Runtime Manager.

The get factory method instantiates a PerProcessInstanceRuntimeManager object. This object will keep a reference of which session started which process instance. If it is a nonpersistent environment, the reference will be kept in an internal HashMap. If it is uses persistence, the reference is kept on a JPA-managed table called ContextMappingInfo as well, but is cached internally to minimize database use.

The PerProcessInstanceRuntimeManager will require a context parameter to retrieve the RuntimeEngine instance associated to a specific process instance ID. If we want to start using a new KIE session, we can request a runtime engine with a fresh session by using the EmptyContext instance. This is usually the practice to start a new process:

RuntimeEngine engine = manager.getRuntimeEngine(EmptyContext.get());
ProcessInstance pInst = engine.getKieSession().startProcess("procId");
Long procInstId = pInst.getId();
manager.disposeRuntimeEngine(engine);

However, if we want to retrieve the same session that started a previous process instance, we can retrieve it with the process instance ID and the help of a context class called ProcessInstanceIdContext:

Long procInstId = ... // process instance ID provided by code
RuntimeEngine engine2 = manager.getRuntimeEngine(   
        ProcessInstanceIdContext.get(procInstId));
engine2.getKieSession().getProcessInstance(procInstId);

Even if the PerProcessInstanceRuntimeManager object can return a new session for each process instance we manually start, this is not mandatory. There is no limitation to the number of process instances a KIE session could use. Also, process instances started by internal process signaling and subprocesses will end up sharing the same KIE session. Nevertheless, each new process instance will register a new mapping between the KIE session and the new process instance, which means that you can use the ProcessInstanceIdContext to retrieve the specific KIE session.

Also, if you wanted to explicitly create a process instance in the same session where another one resides, you could just get the RuntimeEngine instance using the process instance ID of the previous process instance and start the new process in its session:

RuntimeEngine engine = manager.getRuntimeEngine(
        EmtpyContext.get());
ProcessInstance inst1 = engine.getKieSession().
        startProcess("procId");
Long oldProcInstId = inst1.getId();
manager.disposeRuntimeEngine(engine);
RuntimeEngine reuseEngine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(oldProcInstId));
ProcessInstance inst2 = reuseEngine.getKieSession().
        startProcess("procId");

This allows for a greater control over which process instances are executed in each session. We can have several groups of process instances running in parallel in multiple KIE sessions that can run in multiple threads, which allows for better performance and scalability. Process instances inside the same session can share events and rule data between each other.

However, we must understand that process instances residing in a different KIE session will not have this data available unless we explicitly share it through our own code. We must explicitly search for KIE sessions using process instance IDs, which means that we must store other details associated to the mapping we want to keep elsewhere. The Per Process Instance Runtime Manager is a component that sacrifices a little of this ease of use in exchange for better performance (by providing the possibility of having multiple sessions).

The CDI injection

CDI annotations are provided as well for PerProcessInstanceRuntimeManager. To distinguish it from other types of runtime managers, you should mark it with both the @javax.inject.Inject annotation and the @org.kie.internal.runtime.manager.cdi.qualifier.PerProcessInstance annotation. CDI initialization will inject a PerProcessInstanceRuntimeManager instance without having to declare its specific type. It can mark a RuntimeEnvironment instance as well:

@Inject @PerProcessInstance
RuntimeManager manager;
@Inject @PerProcessInstance
RuntimeEnvironment environment;

Remember that CDI is called upon initialization, so always inject the manager but not the RuntimeEngine instance.

Tip

For the RuntimeEnvironment injected instance in CDI, you could use multiple annotations for the different runtime manager types. The following code is completely valid and often used in test cases:

@Produces
@Singleton @PerProcessInstance @PerRequest
public RuntimeEnviornment createEnv() {
    return RuntimeEnvironmentBuilder.Factory.get().
        newDefaultBuilder().get();
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset