With the endless possibilities of BPM 11g topics to write about I found myself a little overwhelmed with the number of topics to discuss, the amount of depth involved concerning some topics, and whether or not the topic has a desirable level of enjoyment or usefulness to a reader. Normally, I would not put too much concern in picking a topic. If there is a BPM topic that is important and should be discussed I have always felt that it should be discussed. However, last week I presented on an extremely important problem we face on project engagements, a resolution to the problem, and all of the gory details that could scare even the most fearless IT people around. My presentation topic was extremely important but despite a wealth of information and examples for dealing with the problem, I noticed that I had no way of making the topic enjoyable or immediately useful.
Internally at Avio we must simply endure such a topic to effectively do our jobs. I have accepted that reality, but rest assured that I am making a conscious effort to keep from subjecting the Avio blog reader to any such situation :) Anyhow, this topic is to be one of hopefully many "Quick Tip" topics that I plan to create. The idea behind my Quick Tip blog topics is to provide a minimal yet effective amount of content concerning a project relevant topic, in a way that is immediately useful, applicable, and enjoyable to the reader.
And now the Quick Tip topic:
Oracle BPM 11g - Making BPM Process Instance Creation Synchronous
Why do this? - With any BPM process that is initiated via a Web Service call and the BPM Start message event, it is a best practice to return some information that helps us identify the BPM and Composite instance(s) that are created as well as knowing whether or not the BPM process invocation and instance creation was successful.
In the following example I will demonstrate:
- Making an existing process synchronous upon Start event invocation
- Return the Composite Instance Id (important for tracking and troubleshooting via EM), and the BPM Instance Id upon process invocation
- The use of an improvised dehydration point to maximize performance and avoid unexpected/unwanted transactionality behavior
Let's review an existing Asynchronous BPM process I have created. Notice that I have opened the "Start" event that initiates the process. You can see that the Start event is set up as being Asynchronous.
Let's begin transforming this process into a Synchronous process that immediately returns the Composite Instance Id and the BPM Instance Id.
- In the Open "Start" event, under the "Advanced" section click the "Synchronous" radio button option and then click OK. The Start event will now display a red error "X" icon and complain about the need for a throw message event. We will resolve this error in the next steps.
- Now go to Component Palette->Events->Throw Events and drag & drop a "Message Event" onto the transition just after the "Start" event. Make sure that the event properly connects to the transition.
- The Properties window should open automatically for the Throw Message event that has just been dropped. Click the "Implementation" tab. Now click the "Continues" radio button option and notice that the "Initiator Node" select field defaults to the first possible event in the process which happens to be the "Start" event.
- Now use the green + icon and add two arguments: 1) bpmInstanceId, 2)compositeInstanceId . It is fine that they are both of String type though technically they are integers. These arguments will be our synchronous return payload information for the process service call.
- Now check the "Use Associations" check box and then click the Edit pencil Icon. The "Data Associations" editor will open. Here we will begin populating the values for the "bpmInstanceId" and "compositeInstanceId" arguments.
- Click the "Expression Builder" Icon for the "bpmInstanceId" argument. The expression builder will open. 1)Switch the "Mode" to "XPath Exp.", 2)Change to the "BPEL XPath Extension Functions" in the "Functions" select box, 3)Find and select the "getInstanceId" function, and 4) Click the "Insert Into Expression" bar to put the "ora:getInstanceId()" function code into the "Expression" field. Finally click OK, and you will be taken back to the "Data Associations" editor.
- Now back in the "Data Associations" editor, click the "Expression Builder" icon for the "compositeInstanceId" argument. The expression builder will open. 1)Switch the "Mode" to "XPath Exp.", 2)Stay in the "Advanced Functions" category of the "Functions" select box, 3)Find and select the "getCompositeInstanceId" function, and 4) Click the "Insert Into Expression" bar to put the "ora:getCompositeInstanceId()" function code into the "Expression" field. Finally click OK, and you will be taken back to the "Data Associations" editor.
- The bpm instance Id and the composite instance Id should now be properly mapped. Click OK to be brought back to the "Properties" editor where you will click OK again to see that the process no longer complains with the red warning symbol on the "Start" event.
- The process model is now setup to be invoked via a Web Service call and will return synchronously with the Bpm Instance Id and Composite Instance Id for the process invocation. The process will conceptually behave in the following manner. 1)The Start event is invoked via a Web Service call and will create a BPM Instance. 2)The ThrowEvent event will fetch the Bpm Instance Id and the Composite Instance Id and will return the Ids as the response payload to the Web Service call that invoked the Start event. 3)The BPM instance will execute the Set Composite Name Field script activity. 4) Finally the BPM instance will finish with the execution of the End event.
The actual behavior is not actually the same as what is described above.
IMPORTANT TRANSACTIONALITY POINTS STARTING NOW
- The actual behavior of the process model is the following. 1) The Start event is invoked via a Web Service call and will create a BPM Instance. 2)The ThrowEvent event will fetch the Bpm Instance Id and the Composite Instance Id and set the return arguments with the values and prepare to reply. 3)The BPM instance will execute the Set Composite Name Field script activity. 4) The BPM instance will execute of the End event and terminate. 5)Finally, The ThrowEvent event will return the arguments/Ids as the response payload to the Web Service call that invoked the Start event.
The actual behavior seems odd but is actually occurring as BPM/SOA 11g intends due to the way transactions are handled for a BPM 11g process model.
- The BPM 11g process models will be executed in as few transactions (or transaction chains) as possible. In the case of the process shown in this topic, all event and activity execution is lumped into a single transaction chain and that is why the ThrowEvent does not immediately reply when the event is invoked.
- In this topic example we want the reply for the Web Service to occur as soon as possible! At the time of writing this post (9-8-2011 with 184.108.40.206.0 being the latest release) there is no Dehydration activity that can be applied in a BPM process model to force the commit of an open transaction chain in BPM. It is good to know that natural dehydration points occur when a BPM instance encounters an Interactive Activity (a green activity invoking a Human Task definition) or a Timer event, and maybe some other events (feel free to explore). With this knowledge we can use the Timer event as a poor man's dehydration activity like in the following steps.
- Go to Component Palette->Events->Catch Events and drag and drop a "Timer" event into the transition after the "ThrowEvent" event. Set the Timer event for 1 second and click OK.
A single second will not make a difference in this process and in approximately 99% of the business use cases I have encountered over the years and I'm sure I could use the Expression settings of the Timer event to reduce the time from 1 second to any number of milliseconds but this is just a simple example so I will leave that exercise up to someone else to play with :)
- Now with our improvised dehydration point setup the actual behavior of the process will be the same as the conceptual behavior explained above.
From conceptual behavior to actual behavior:
1)The Start event is invoked via a Web Service call and will create a BPM Instance. 2)The ThrowEvent event will fetch the Bpm Instance Id and the Composite Instance Id and will return the Ids as the response payload to the Web Service call that invoked the Start event. 3)The BPM instance will execute the Set Composite Name Field script activity. 4) Finally the BPM instance will finish with the execution of the End event.
- What do we gain with the process being broken into two transactions? The biggest gain is with the Web Service performance that invokes the BPM Process. In this simple example the performance of the Web Service invocation and creation of the BPM instance is not noticed. However, the performance would be noticed in a process that contains a number of script activities, external service invocations, business rule calls, and/or more activities before a natural dehydration point is encountered. Another gain is that we avoid potentially rolling back the Web Service execution and instance creation behavior should an activity or event fail after the reply to the process Web Service. Without a dehydration point all additional activity execution could/would be chained into our Web Service invocation and instance creation transaction. If any of the additionally chained in transactions should happen to fail then it could rollback all of the transactions in the chain or interfere with the act of creating the BPM instance, which in most cases is not a desirable outcome.
Once again, the goal here is to create a BPM Process with synchronous instance creation and invocation which returns the Composite Instance ID and the BPM Instance ID.
A BPM process is very rarely synchronous in a manner that has the BPM process starting, executing, and finishing in less than 20 seconds with a reply of the entire process outcome. Due to the nature of BPM processes needing to run for an extended period of time, the concept of a synchronous process is actually nothing more than a process that is invoked asynchronously and will perform a callback/reply at some time in the future when all process steps have been completed. It is a best practice to make the BPM process invocation synchronous whether the end of the process performs a service callback or not. Thanks :)