cancel
Showing results for 
Search instead for 
Did you mean: 

BPM runtime information - timing of database commit

kkompel
Champ in-the-making
Champ in-the-making
Hi, we are using Activiti 5.11 and are modeling a business process with three tasks:
Task 1 - Java service task that sends a JMS message
Task 2 - Receive Task that puts the BPM in a 'wait' state
Task 3 - Java service task that gets called by the JMS listener for the message sent in Task 1; this task looks up the appropriate BPM instance (based on process instance id, which is sent as part of the JMS message), and signals it to resume.

The issue we are seeing is that the BPM runtime information is not being written to the database until Task 2 completes.  However, when Task 1 sends the JMS message, Task 3 is almost instantaneously firing and trying to signal the BPM to resume – since Task 2 has not yet completed, Task 3 does not find any Activiti runtime information in the database and therefore throws an exception.

Now, we can solve this problem by introducing a latency in Task 3, or checking the database for runtime information before trying to signal the BPM in Task 3.  However, we are wondering if there is a better way to do this?  Ideally, we want to make sure the BPM runtime information has been written to the database *before* sending the JMS message –
* Can we force the process instance to commit in Task 1 or Task 2, and then send our message?
* Can we attach an execution listener to the receive task "end" event (Task 2), so that we can send our message at that point (after database commit)? (I tried, but was able to attach an execution listener only to the Task 2 "start" event.)

Another possibility could be to somehow integrate the BPM/messaging with Mule (which is also in our architecture) if that can give us better control over the database commits and message firing, but we haven't explored this.

FYI, we are using an Oracle database for Activiti, and our spring process engine configuration uses Spring's DataSourceTransactionManager.

Any help with this issue will be much appreciated.
10 REPLIES 10

gokceng1
Champ in-the-making
Champ in-the-making
We are implementing something similar. In our case we are firing a message to the JMS queue, after that there comes a receive task or a message catching event. When reply returns, we find the process as you do and trigger it with the payload. I don't think java service task is useful for your scenario. I've faced this 'flush' problem in another case. You need to have a wait state like those to overcome this. Form user guide:

It's important to note that the Activiti engine will continue process execution steps until it reaches a wait state, such as the user task. At such a wait state, the current state of the process instance is stored in the database.

You can search for 'wait state' in user guide.

kkompel
Champ in-the-making
Champ in-the-making
Thanks for the reply.  Task 2 (after the JMS message is sent from Task 1) is already a Receive task, so it is indeed putting the BPM in a wait state and writing to the database.  The problem is that the listener for the JMS message is triggered *before* Task 2 has had a chance write to the database; so in the listener if we try to look up any information about the process instance from the database, it throws an exception.

(I am editing the original post to indicate more clearly that Task 2 is a Receive Task, not a Java service task)

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
Why is there a waitstate if things go so quickly?

But anyway, What you should do is make the putting of the message in the jms queue use the same transaction as the engine. That way the message is actually put in the queue (committed) when task2 is done.

kkompel
Champ in-the-making
Champ in-the-making
Task 1 is sending the JMS message and Task 2 is the Receive task, both in the same BPM, so they should both be in the same transaction already..?

frederikherema1
Star Contributor
Star Contributor
Again, as long as a process hasn't reached a wait-state, they transaction is NOT YET committed. The (external) signal-trigger from the API uses a different transaction. This is what transactions are supposed to do: isolate uncommitted changes from independent operations to prevent oncomitted-data reads.

A receive-task is designed to respond to external process-events, which can occur at any point time and require the state to be committed. This is just the way it is…

Possible solutions to your problem:

  • Use a service-task instead of a receive-task that does some kind of polling (with potential timeout) for the message to arrive. This will ensure the Task2 is executed in the same transaction as Task1. Keep in mind, this keeps open a transaction/db-connection for potentially a long time.

  • Make the piece of logic that calls the "signal" smarter and build in a retry-mechanism in case the response comes back quicker than activiti can finish the process. In activiti-terms, the process isn't waiting until the transaction is committed.

kkompel
Champ in-the-making
Champ in-the-making
Thank you for the reply.  We did end up building retry-logic in the code before signalling the BPM to resume (to ensure that the required data is in the database from Task 2); thanks for validating that this is indeed [one of] the preferred approach.

groopk
Champ in-the-making
Champ in-the-making
We are implementing this type of logic with a userTask for a "system" user. We put a listener on the task assignment that shoots off a JMS message to invoke the remote service.  Then when other service is done, it simply completes the task and the workflow continues.  Kind of modeling the way amazon workflow service handles tasks. It makes for nice transaction boundaries and nice tracking of work that is in progress.

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
Task 1 is sending the JMS message and Task 2 is the Receive task, both in the same BPM, so they should both be in the same transaction already..?

No, the CREATION of te receivetask should be in the same transaction. Not the execution of it. The timing 'problem' disappears then.

This is btw not a specific Activiti issue. Would happen in many similar other circumstances as well.

kkompel
Champ in-the-making
Champ in-the-making
Do you have a code sample for programmatically creating a receive task or putting a process instance in "wait" state?  I tried the 'suspend' and 'reactivate' actions on the runtime service but they are not helping.