As explained in the section called “Graph execution” and
???, jBPM runs the process in the thread of
the client and is by nature synchronous. Meaning that the token.signal()
or taskInstance.end()
will only return when the process has entered a new
wait state.
The jPDL feature that we describe here from a modelling perspective is Chapter 13, Asynchronous continuations.
In most situations this is the most straightforward approach because the process execution can easily be bound to server side transactions: the process moves from one state to the next in one transaction.
In some scenarios where in-process calculations take a lot of time, this behaviour might be undesirable. To cope with this, jBPM includes an asynchronous messaging system that allows to continue a process in an asynchronous manner. Of course, in a java enterprise environment, jBPM can be configured to use a JMS message broker instead of the built in messaging system.
In any node, jPDL supports the attribute async="true"
.
Asynchronous nodes will not be executed in the thread of the client. Instead, a message is
sent over the asynschronous messaging system and the thread is returned to the client
(meaning that the token.signal()
or taskInstance.end()
will return).
Note that the jbpm client code can now commit the transaction. The sending of the
message should be done in the same transaction as the process updates. So the net result of
the transaction is that the token has moved to the next node (which has not yet been executed)
and a org.jbpm.command.ExecuteNodeCommand
-message has been sent on the
asynchronous messaging system to the jBPM Command Executor.
The jBPM Command Executor reads commands from the queue and executes them. In the case
of the org.jbpm.command.ExecuteNodeCommand
, the process will be continued
with executing the node. Each command is executed in a separate transaction.
So in order for asynchronous processes to continue, a jBPM Command Executor needs to
be running. The simplest way to do that is to configure the CommandExecutionServlet
in your web application. Alternatively, you should make sure that the CommandExecutor thread is
up and running in any other way.
As a process modeller, you should not really be concerned with all this asynchronous
messaging. The main point to remember is transaction demarcation: By default jBPM will operate
in the transaction of the client, doing the whole calculation until the process enters a wait
state. Use async="true"
to demarcate a transaction in the process.
Let's look at an example:
... <start-state> <transition to="one" /> </start-state> <node async="true" name="one"> <action class="com...MyAutomaticAction" /> <transition to="two" /> </node> <node async="true" name="two"> <action class="com...MyAutomaticAction" /> <transition to="three" /> </node> <node async="true" name="three"> <action class="com...MyAutomaticAction" /> <transition to="end" /> </node> <end-state name="end" /> ...
Client code to interact with process executions (starting and resuming) is exactly the same as with normal (synchronous) processes:
...start a transaction... JbpmContext jbpmContext = jbpmConfiguration.createContext(); try { ProcessInstance processInstance = jbpmContext.newProcessInstance("my async process"); processInstance.signal(); jbpmContext.save(processInstance); } finally { jbpmContext.close(); }
After this first transaction, the root token of the process instance
will point to node one
and a
ExecuteNodeCommand
message will have been sent to the
command executor.
In a subsequent transaction, the command executor will read the message
from the queue and execute node one
. The action can decide to
propagate the execution or enter a wait state. If the action decides to propagate
the execution, the transaction will be ended when the execution arrives at
node two. And so on, and so on...