Chapter 17. Persistence

The runtime data of the Process Engine can be persisted in data stores. The persistence mechanism saves the data using marshalling: the runtime data is converted into a binary dataset and the dataset is saved in the data storage.

Note that persistence is not configured by default and the engine runs without persistence.

Custom marshalling mechanism

The runtime data is saved using marshalling (binary persistence). The marshalling mechanism is a custom serialization mechanism.

Red Hat JBoss BPM Suite will persist the following when persistence is configured:

  • Session state: This includes the session ID, date of last modification, the session data that business rules would need for evaluation, state of timer jobs.
  • Process instance state: This includes the process instance ID, process ID, date of last modification, date of last read access, process instance start date, runtime data (the execution status including the node being executed, variable values, etc.)and the eventtypes.
  • Work item runtime state: This includes the work item ID, creation date, name, process instance ID, and the work item state itself.

Based on the persisted data, it is possible to restore the state of execution of all running process instances in case of failure or to temporarily remove running instances from memory and restore them later. By default, no persistence is configured.

To allow persistence, you need to add the jbpm-persistence jar files to the classpath of your application and configure the engine to use persistence. The engine automatically stores the runtime state in the storage when the engine reaches a safe point. Safe points are points where the process instance has paused. When a process instance invocation reaches a safe point in the engine, the engine stores any changes to the process instance as a snapshot of the process runtime data. However, when a process instance is completed, the persisted snapshot of process instance runtime data is automatically deleted.

If a failure occurs and you need to restore the engine runtime from the storage, the process instances are automatically restored and their execution resumes so there is no need to reload and trigger the process instances manually.

The runtime persistence data is to be considered internal to the engine. You should not access persisted runtime data or modify them directly as this might have unexpected side effects.

To obtain information about the current execution state, refer to the history log. Query the database for runtime data only if absolutely necessary.

17.1. Session

Sessions are persisted as SessionInfo entities. These persist the state of the runtime KIE session, and store the following data:

FieldDescriptionNullable

id

primary key

false

lastmodificationdate

last saved to data store

N/A

rulesbytearray

binary dataset with session state (binary blob

false

startdate

session start

 

optlock

version number used to lock value for optimistic locking

 

17.2. Process Instance

Process instances are persisted as ProcessInstanceInfo entities, which persist the state of a process instance on runtime and store the following data:

FieldDescriptionNullable

instanceid

primary key

false

lastmodificationdate

last saved to data store

N/A

lastreaddate

last read from data store

N/A

processid

ID of the process the instance is based on

false

processinstancebytearray

binary dataset with process instance state (binary blob)

false

startdate

Process instance start date

 

optlock

version number used lock value for optimistic locking

 

state

Process instance state

false

ProcessInstanceInfo has a 1:N relationship to the EventTypes entity.

The EventTypes entity contains the following data:

FieldDescriptionNullable

instanceid

reference to the Process instance (foreign key to the processinstanceinfo)

false

element

text field related to an event the Process instance has undergone

 

Pessimistic Locking Support

The default locking mechanism for persistence of processes is optimistic. With multi-thread high concurrency to the same process instance, this locking strategy can result in bad performance.

With the release of the 6.1 version of Red Hat JBoss BPM Suite, this can be changed at runtime to allow the user to set locking on a per process basis and to allow it to be pessimistic (the change can be made at a per KIE Session level or Runtime Manager level as well and not just at the process level).

To set a process to use pessimistic locking, do this in the runtime environment:

import org.kie.api.runtime.Environment;
import org.kie.api.runtime.EnvironmentName;
import org.kie.api.runtime.manager.RuntimeManager;
import org.kie.api.runtime.manager.RuntimeManagerFactory;

...

// here env is an instance of org.kie.api.runtime.Environment
env.set(EnvironmentName.USE_PESSIMISTIC_LOCKING, true);

// now create your Runtime Manager using this environment
RuntimeManager manager = RuntimeManagerFactory.Factory.get().newPerRequestRuntimeManager(environment);

17.3. Work Item

Work Items are persisted as workiteminfo entities, which persist the state of the particular work item instance on runtime and store the following data:

FieldDescriptionNullable

workitemid

primary key

false

name

work item name

 

processinstanceid

parent Process instance id

false

state

integer representing work item state

false

optlock

version number used lock value for optimistic locking

 

workitembytearray

binary dataset with work item state (binary blob)

false

creationDate

timestampe on which the work item was created

false

17.4. Persistence configuration

17.4.1. Persistence configuration

Although persistence is not used by default, the dependencies needed are available in the runtime directory as jar files.

Persistence is defined per session and you can define it either using the JBPMHelper class after you create a session or using the JPAKnowledgeService to create your session. The latter option provides more flexibility, while JBPMHelper has a method to create a session, and uses a configuration file to configure this session.

17.4.2. Configuring persistence using JBPMHelper

To configure persistence of your session using JBPMHelper, do the following:

  1. Define your application to use an appropriate JBPMHelper session constructor:

    • KieSession ksession = JBPMHelper.newKieSession(kbase);
    • KieSession ksession = JBPMHelper.loadKieSession(kbase, sessionId);
  2. Configure the persistence in the jBPM.properties file.

    Example 17.1. A sample jBPM.properties file with persistence for the in-memory H2 database

    # for creating a datasource
    persistence.datasource.name=jdbc/jbpm-ds
    persistence.datasource.user=sa
    persistence.datasource.password=
    persistence.datasource.url=jdbc:h2:tcp://localhost/~/jbpm-db
    persistence.datasource.driverClassName=org.h2.Driver
    
    # for configuring persistence of the session
    persistence.enabled=true
    persistence.persistenceunit.name=org.jbpm.persistence.jpa
    persistence.persistenceunit.dialect=org.hibernate.dialect.H2Dialect
    
    # for configuring the human task service
    taskservice.enabled=true
    taskservice.datasource.name=org.jbpm.task
    taskservice.transport=mina
    taskservice.usergroupcallback=org.jbpm.task.service.DefaultUserGroupCallbackImpl

Any invocations on the session will now trigger the persistence process.

Make sure the datasource is up and running on engine start. If you are running the in-memory H2 database, you can start the database from your application using the JBPMHelper.startH2Server(); method call and register it with the engine using JBPMHelper.setupDataSource(); method call.

17.4.3. Configuring persistence using JPAKnowledgeService

To create your knowledge session and configure its persistence using JPAKnowledgeService, do the following:

  1. Define your application to use the knowledge session created by JPAKnowledgeService:

    1. Define the session based on a knowledge base, a knowledge session configuration, and an environment. The environment must contain a reference to your Entity Manager Factory:

      // create the entity manager factory and register it in the environment
      EntityManagerFactory emf = Persistence.createEntityManagerFactory( "org.jbpm.persistence.jpa" );
      Environment env = KnowledgeBaseFactory.newEnvironment();
      env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, emf );
      
      // create a new knowledge session that uses JPA to store the runtime state
      KieSession ksession = JPAKnowledgeService.newKieSession( kbase, null, env );
      int sessionId = ksession.getId();
      
      // invoke methods on your method here
      ksession.startProcess( "MyProcess" );
      ksession.dispose();
    2. Define the session based on a specific session id.

      // recreate the session from database using the sessionId
      ksession = JPAKnowledgeService.loadKieSession(sessionId, kbase, null, env );
  2. Configure the persistence in the META-INF/persistence.xml file: configure JPA to use Hibernate and the respective database.

    Information on how to configure data source on your application server should be available in the documentation delivered with the application server. For this information for JBoss Enterprise Application Platform, see the Administration and Configuration Guide for this product.

    Example 17.2. A sample persistence.xml file with persistence for an H2 data source jdbc/jbpm-ds

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <persistence
      version="1.0"
      xsi:schemaLocation=
        "http://java.sun.com/xml/ns/persistence
         http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd
         http://java.sun.com/xml/ns/persistence/orm
         http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
      xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns="http://java.sun.com/xml/ns/persistence">
      <persistence-unit name="org.jbpm.persistence.jpa" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>jdbc/jbpm-ds</jta-data-source>
        <mapping-file>META-INF/JBPMorm.xml</mapping-file>
        <class>org.drools.persistence.info.SessionInfo</class>
        <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class>
        <class>org.drools.persistence.info.WorkItemInfo</class>
        <properties>
          <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
          <property name="hibernate.max_fetch_depth" value="3"/>
          <property name="hibernate.hbm2ddl.auto" value="update"/>
          <property name="hibernate.show_sql" value="true"/>
          <property name="hibernate.transaction.manager_lookup_class"
                    value="org.hibernate.transaction.BTMTransactionManagerLookup"/>
        </properties>
      </persistence-unit>
    </persistence>

Any invocations on the session will now trigger the persistence process.

Make sure the datasource is up and running on engine start. If you are running the in-memory H2 database, you can start the database from your application using the JBPMHelper.startH2Server(); method call and register it with the engine using JBPMHelper.setupDataSource(); method call.

Sample data source configuration for simple Java environment

If you are running JBoss BPM Suite in a simple Java environment, your data source configuration will be similar to the following:

PoolingDataSource ds = new PoolingDataSource();
ds.setUniqueName("jdbc/jbpm-ds");
ds.setClassName("bitronix.tm.resource.jdbc.lrc.LrcXADataSource");
ds.setMaxPoolSize(3);
ds.setAllowLocalTransactions(true);
ds.getDriverProperties().put("user", "sa");
ds.getDriverProperties().put("password", "sasa");
ds.getDriverProperties().put("URL", "jdbc:h2:tcp://localhost/~/jbpm-db");
ds.getDriverProperties().put("driverClassName", "org.h2.Driver");
ds.init();