Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
0 Kudos
The execution of an aBPM/BPM Process start will typically be done automatically by the aBPM framework or manually by the start implementation inside of an aBPM scenario. Inside of heavy-load system situations it can occurs that exceptions will be produced and side-effects appears with the effect that additional custom start implementation around the aBPM framework will catch those exceptions and triggers a second or a multiple start of the same process with identical content but with different aBPM process/BPM process instance ids or no process was started.

In this article you will learn a proven workaround to prevent double or multiple starts of aBPM/BPM processes for one unique trigger identifier and you learn to prevent to check that no process was started with the help of aBPM database table selects.

Theoretical background


One trigger with a unique identifier will be send from an external system or a unique identifier will be created inside of the Start state of the aBPM scenario. This unique identifier field is defined inside of the scenario definition/scenario spread sheet and will be set and persist as attribute inside of the BO for the aBPM process.

A typically command line outside of the <aBPMScenario>ExtBase for the start could be:
ABPMProcess process = new ABPMProcess(bo, processStarterPrincipalName, "<ScenarioDisplayname>", "<ScenarioDescription>");
<aBPMScenario>ExtBase base = new <aBPMScenario>ExtBase();
base.start<CustomOperation>(process, Locale.GERMAN);

 

And contains e.g. the following content inside of <aBPMScenario>ExtBase:
public void start<CustomOperation>(ABPMProcess process, Locale locale) throws Exception {
Exception e = this.startProcess(process, locale);
if (null != e) {
throw e;
}
}

 

Prevention workaround before and after start operation


To prevent a double/multi start of the same aBPM/BPM process with the same content it is necessary to check before the start operation if an aBPM process still exists in the system.
For this a SQL select like this should be executed (name: SQL_READ_BPM_PROCESS_ID_BY_CRITERIAS😞
SELECT BPM_PROCESS_ID FROM Y_ABPM_PROCESS WHERE ID IN (SELECT A.PROCESS_FK FROM Y_ABPM_AT A, Y_ABPM_AT B, Y_ABPM_AT C WHERE A.PROCESS_FK = B.PROCESS_FK AND A.PROCESS_FK = C.PROCESS_FK AND B.PROCESS_FK = C.PROCESS_FK AND A.TECHNICAL_NAME = '<name of your first scenario field>' AND A.STRING_CV_SEARCH = '<value of first field, e.g. unique identifier>' AND B.TECHNICAL_NAME = '<name of your second scenario field>' AND B.STRING_CV_SEARCH = '<value of second field, e.g. another identifier/content>' AND C.TECHNICAL_NAME = '<name of your third scenario field>' AND C.STRING_CV_SEARCH = '<value of third field, e.g. another identifier/content>')

Hint: The select above contains an example with 3 identifiers, in case you have less or more please adjust the SQL statement to your requirements.

Hint: The field STRING_CV_SEARCH was created inside Y_ABPM_PROCESS to execute searches must faster than the field that contains the current or original value. The content of field STRING_CV_SEARCH is always upper case. That is the reason why the code snippet below has .toUpperCase() to set values.

The start implementation should be extended with the following code snippet like this:
// execute check before start
String sqlString = MessageFormat.format(SQL_READ_BPM_PROCESS_ID_BY_CRITERIAS, ((String) <value of your first parameter>).toUpperCase(), ((String) <value of your second parameter).toUpperCase(), ((String) <value of your third parameter).toUpperCase());
List<String> bpmProcessIDs = ...execute the SQL select;
if (!bpmProcessIDs.isEmpty()) {
...do something to check if existing BPM processes are no longer running if yes throw an exception...
}

...
// execute start operations
ABPMProcess process = new ABPMProcess(bo, processStarterPrincipalName, "<ScenarioDisplayname>", "<ScenarioDescription>");
<aBPMScenario>ExtBase base = new <aBPMScenario>ExtBase();
base.start<CustomOperation>(process, Locale.GERMAN);
...

// execute check after start
bpmProcessIDs = ...execute the SQL select again;
if (!bpmProcessIDs.isEmpty()) {
...do something to check if one BPM process has status InProgress, Failed, Suspended or InError (-> that means that the start of the BPM process some lines above was executed successfully, if no process has these states no BPM process was started, in this case throw an exception
} else {
...throw an exception for non started process
}

The check after the execution of the start operations is relevant to guarantee that the start was executed successfully once. If this check will not be done e.g. an initial external trigger could be dropped from the system and no running BPM process exists for this trigger message.

Conclusion


At the first view of this workaround it is maybe a little bit disturbing to check inside of your scenario/narrow implementation to the scenario implementation if the start of the BPM process was successfully or not. But when you doesn't check this inside of heavy-load situations it can result into strange behaviors or zombie situations were more than one process was started. In one of my projects we have had such effects in the productive systems and with additional security layers (in case of exceptions store the trigger message into a JMS queue and a MessageDrivenBean tries the start again) around the above workaround we were amazed why double or multiple start of one trigger message occurs in the system.