We have found same error in load testing of our application. However we noticed the data used was very less compared to vusers and duration of load test. But nothing to worry, need to have user retry it.
Actually your assumption that the first user who executes step 3 wins is not always correct. May be most of the time it happens that way for your case.
It has to be that the first of the two treads which does a hibernateSession.flush() will win. This is a desired behaviour from hibernate, and this is a very important feature.
I think the solution you thought of catching StaleObjectStateException is fair enough. Make sure that your "try" boundary is the smallest possible so that you do not catch StaleObjectStateException happening because of some other reason.
I think eventually jBPM should be able to cope with this situation and return a more batural error like "task already taken by ...."
Maybe you should create a JIRA issue asking the developers to investigate this.
no, discuss this on the dev forum first
This is a nice feature to have, specially if you need to show something on the UI.
But, this will be very difficult to achieve as well. With FlushMode.Auto, hibernate can do a flush at any point it thinks suitable. So when you call "takeTask" method, hibernate may not complain at all, but at some later point it, when it tries to clear the action queue, then it will complain. So you never know when this exception comes.
One strategy for this might be is to have an exception translator at the DBSession level. But that will be almost as generic as Hibernate exception translator. So whether the Task is taken by somebody or something else happened to the task will be difficult to decide.
But the flip side of this is, a generic exception is caught to give some message which is more context specific then re-thrown - this will also pollute the exception stack trace a bit. As a developer, who is using Jbpm API, I wont like that to happen. I personally would prefer to deal in StaleObjectStateException and inspect what is stale and why. Custom exception on top of that may make finding to root cause a bit difficult for a developer.