A few weeks back we had the opportunity to participante in an 12c challenge which had lots of different flavours (BPM, Coherence, ADF, etc.) and some very strict performance requirements.
Scenario
In this solution, an operator would be logged on to an ADF application showing different regions, with one particular region that would update as the BPM instance progressed through the different human tasks in the process. The team had opted for a simple solution to find out when a BPM instance had reached a human task: to poll the engine until a task was found.
The problem
Polling the engine could be a solution if the instance load was low but the objective was to handle thousands of short-lived instances in parallel, which would overload the engine with queries. In addition, there was the issue of having to wait an interval which resulted in additional time loss.
As with most push/pull cases, the ideal would be to approach the problem from the other side of the fence: instead of polling for events, pushing them from the BPMN process and reacting to these from the UI side.
For the first part, emitting events when the BPM tasks arrives at a human task would be straight-forward: the Human Workflow API provides a series of callback events that can be used, with the onAssigned
event being the one to use. Therefore, the remaining question was how to receive and process events on the ADF side.
The solution
From the requirements, we needed a way to react when an event was received. This immediately lead to using JavaScript, as it is well supported in ADF. The only question left was what type of event to receive.
The answer lies in a new Weblogic 12c "native" feature: web-sockets (we can use web-sockets in 11g using Jersey as well). JavaScript can handle opening new sockets and listening for messages.
We developed a Web Socket application that would enable a server endpoint for every BPM instance (remember these are short-lived instances, thus there is no risk of running out of resources).
As the ADF app was responsible for creating BPM instances with a correlation key, it connected to the server endpoint using that very same key, effectively establishing a direct connection to the endpoint with its own channel.
On the server side, every onAssigned
event that would be received by the human task callback class would publish a new message to the endpoint (using the same correlation key, in this case exposed as a public attribute in the human task) which in turn would be relayed by the server to the ADF UI.
A second improvement
We soon discovered that we didn't even need to wait for the OnAssigned
event: by using a REST API (12c can directly invoke REST services) we could allow the process to notify the UI as soon as possible, therefore shortening the times even more. Thus, two events were sent to the UI: one to notify that the data was available and the second one to enable the UI buttons for processing. By the time the user had read the information displayed on the page, the buttons would be already enabled.
Conclusion
By using web sockets, we are effectively enabling a new channel to allow interested parties to become "aware" of what is happening. Whilst there are multiple ways of doing this - using events, signals, etc. - in this particular scenario the use of web sockets is a very good fit, as it allows ADF to be notified when a region needs to be refreshed.
The end user perception is that we have an extremely fast and smooth user experience, whilst still retaining the benefits of using a BPM engine.
The performance - which was improved around 40% - benefited from:
- removing the polling mechanism, thus eliminating the backend access to the database and the interval waiting
- accessing and displaying data in the end UI as soon as it was available
- using the "thinking time" of the user to allow the process to perform additional operations
And last, but not least, we can think of a very simple additional use-case for web-sockets: to use them in the workspace application to notify when a connected user has a new additional task. We will surely be implementing this feature on our custom workspace - but that will be left for another article.
Until next time,
Fernando