67.3. プロセスエンジンのトランザクション

プロセスエンジンは、Java Transaction API (JTA) トランザクションをサポートします。

プロセスエンジンの現在のバージョンは、純粋なローカルトランザクションをサポートしません。

アプリケーション内にトランザクション境界を指定しないと、プロセスエンジンは、別のトランザクションでプロセスエンジンで各メソッド呼び出しを自動的に実行します。

必要に応じて、アプリケーションコードでトランザクション境界を指定して、複数のコマンドを 1 つのトランザクションに統合できます。

67.3.1. トランザクションマネージャーの登録

ユーザー定義トランザクションを使用するには、環境でトランザクションマネージャーを登録する必要があります。

以下のサンプルコードはトランザクションマネージャーを登録し、JTA 呼び出しを使用してトランザクション境界を指定します。

トランザクションマネージャーの登録およびトランザクションの使用

// Create the entity manager factory
EntityManagerFactory emf = EntityManagerFactoryManager.get().getOrCreate("org.jbpm.persistence.jpa");
TransactionManager tm = TransactionManagerServices.getTransactionManager();

// Set up the runtime environment
RuntimeEnvironment environment = RuntimeEnvironmentBuilder.Factory.get()
.newDefaultBuilder()
.addAsset(ResourceFactory.newClassPathResource("MyProcessDefinition.bpmn2"), ResourceType.BPMN2)
    .addEnvironmentEntry(EnvironmentName.TRANSACTION_MANAGER, tm)
    .get();

// Get the KIE session
RuntimeManager manager = RuntimeManagerFactory.Factory.get().newPerRequestRuntimeManager(environment);
RuntimeEngine runtime = manager.getRuntimeEngine(ProcessInstanceIdContext.get());
KieSession ksession = runtime.getKieSession();

// Start the transaction
UserTransaction ut = InitialContext.doLookup("java:comp/UserTransaction");
ut.begin();

// Perform multiple commands inside one transaction
ksession.insert( new Person( "John Doe" ) );
ksession.startProcess("MyProcess");

// Commit the transaction
ut.commit();

UserTransactionTransactionManagerTransactionSynchronizationRegistry などのトランザクション関連のオブジェクトが JNDI に登録されているため、root クラスパスに jndi.properties ファイルを指定して JNDI InitialContextFactory オブジェクトを作成する必要があります。

プロジェクトに jbpm-test モジュールが含まれる場合、このファイルはすでにデフォルトで含まれています。

それ以外の場合は、以下の内容で jndi.properties ファイルを作成してください。

jndi.properties ファイルの内容

java.naming.factory.initial=org.jbpm.test.util.CloseSafeMemoryContextFactory
org.osjava.sj.root=target/test-classes/config
org.osjava.jndi.delimiter=/
org.osjava.sj.jndi.shared=true

この設定では、simple-jndi:simple-jndi アーティファクトがプロジェクトのクラスパスにあることを前提としています。異なる JNDI 実装を使用することもできます。

デフォルトでは、Narayana JTA トランザクションマネージャーが使用されます。別の JTA トランザクションマネージャーを使用する場合は、persistence.xml ファイルを変更して必要なトランザクションマネージャーを使用できます。たとえば、アプリケーションが Red Hat JBoss EAP バージョン 7 以降で実行する場合は、JBoss トランザクションマネージャーを使用できます。この場合は、persistence.xml ファイルのトランザクションマネージャープロパティーを変更します。

JBoss トランザクションマネージャーの persistence.xml ファイルのトランザクションマネージャープロパティー

<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />

警告

JTA トランザクション (UserTransaction または CMT) で RuntimeManager クラスの Singleton ストラテジーを使用すると競合状態が作成されます。この競合状態により、Process instance XXX is disconnected と同様のメッセージを含む IllegalStateException 例外が発生する場合があります。

この競合状態を回避するには、ユーザーアプリケーションコードでトランザクションを呼び出す際に、KieSession インスタンスを明示的に同期します。

synchronized (ksession) {
    try {
        tx.begin();

        // use ksession
        // application logic

        tx.commit();
    } catch (Exception e) {
        //...
    }
}

67.3.2. コンテナー管理トランザクションの設定

EJB Bean などの CMT (container-managed transaction) モードで実行するアプリケーションにプロセスエンジンを埋め込む場合は、追加の設定を完了する必要があります。この設定は、アプリケーションが CMT アプリケーションが JNDI から UserTransaction インスタンス (WebSphere Application Server など) にアクセスできないアプリケーションサーバーで実行される場合に特に重要になります。

プロセスエンジンのデフォルトトランザクションマネージャーの実装は、UserTransaction を使用してトランザクションの状態をクエリーし、ステータスを使用してトランザクションを開始するかどうかを判断します。UserTransaction インスタンスにアクセスできない環境では、この実装は失敗します。

CMT 環境で適切な実行を有効にするために、プロセスエンジンは専用のトランザクションマネージャーの実装 (org.jbpm.persistence.jta.ContainerManagedTransactionManager) を提供します。このトランザクションマネージャーはトランザクションがアクティブであることを想定し、getStatus() メソッドが呼び出されると常に ACTIVE を返します。トランザクションマネージャーはコンテナー管理トランザクションモードでこれらの操作に影響を与えることができないため、begincommitrollback などの操作は操作できません。

注記

プロセス中にコードはエンジンによって発生した例外をコンテナーに伝播し、コンテナーがトランザクションを必要に応じてロールバックするようにする必要があります。

このトランザクションマネージャーを設定するには、以下の手順を行います。

手順

  1. コードで、セッションを作成または読み込む前に、トランザクションマネージャーと永続コンテキストマネージャーを環境に挿入します。

    トランザクションマネージャーと永続コンテキストマネージャーの環境への挿入

    Environment env = EnvironmentFactory.newEnvironment();
    env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
    env.set(EnvironmentName.TRANSACTION_MANAGER, new ContainerManagedTransactionManager());
    env.set(EnvironmentName.PERSISTENCE_CONTEXT_MANAGER, new JpaProcessPersistenceContextManager(env));
    env.set(EnvironmentName.TASK_PERSISTENCE_CONTEXT_MANAGER, new JPATaskPersistenceContextManager(env));

  2. persistence.xml ファイルで、JPA プロバイダーを設定します。以下の例では、hibernate および WebSphere Application Server を使用します。

    persistence.xml ファイルでの JPA プロバイダーの設定

    <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.CMTTransactionFactory"/>
    <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.WebSphereJtaPlatform"/>

  3. KIE セッションを破棄する場合は、直接破棄しないでください。代わりに、org.jbpm.persistence.jta.ContainerManagedTransactionDisposeCommand コマンドを実行します。このコマンドは、現在のトランザクションの完了時にセッションが確実に破棄されるようにします。以下の例の ksession は、破棄する KieSession オブジェクトです。

    ContainerManagedTransactionDisposeCommand コマンドを使用した KIE セッションの破棄

    ksession.execute(new ContainerManagedTransactionDisposeCommand());

    プロセスエンジンは、トランザクションの同期を登録してセッション状態をクリーンアップするため、セッションを直接破棄すると、トランザクションの完了時に例外が発生します。

67.3.3. トランザクションの再試行

プロセスエンジンがトランザクションのコミット時に別のトランザクションが同時にコミットされることが原因で、コミット操作に失敗することがあります。この場合、プロセスエンジンはトランザクションを再試行する必要があります。

再試行に複数回失敗すると、トランザクションは完全に失敗します。

JVM システムプロパティーを使用して、再試行プロセスを制御できます。

表67.8 トランザクションのコミットを再試行するシステムプロパティー

プロパティーデフォルト説明

org.kie.optlock.retries

Integer

5

このプロパティーでは、完全に失敗となる前に、プロセスエンジンがトランザクションを再試行する回数を記述します。

org.kie.optlock.delay

Integer

50

最初の再試行までの時間 (ミリ秒単位)。

org.kie.optlock.delayFactor

Integer

4

後続の再試行ごとに遅延時間を長くする乗数。デフォルト値の場合には、プロセスエンジンは、1 回目の再試行まで 50 ミリ秒、2 番目の再試行まで 200 ミリ秒、3 番目の再試行まで 800 ミリ秒待機します。