Overview

Skill Level: Intermediate

Requires prior experience with BPM

There have been notable times when systems, like ICO, attempt to start a BPM BPD instance via the REST API and, for a variety of reasons, two instances are created instead of one. This tutorial addresses one way to remove unexpected duplicates.

Ingredients

  • An active instance of ICO¬†with Self-Service offering creating duplicate instances
  • An active BPM instance with permissions to create and edit BPDs in process designer
  • (examples shown use versions 2.5.0.2 of ICO and 8.5.6 of BPM, other versions may vary)

Step-by-step

  1. Understanding the problem

    The most common cause of duplicate instances is caused by a slowdown in the integration between ICO and BPM. Duplicate instances are most commonly noticed in my experience when the system is running slowly for whatever reason (low memory, high cpu usage, etc.). Because of this BPM takes longer to reply to ICO then expected and the request times out, even though BPM recieved the request and is in the process of creating a new instance (Instance #1). ICO then retries the request immediately and recieves a successful response (Instance #2). At this point ICO only knows that 1 instance succeeded, but on the backend BPM has created 2 identical instances (with different ids). Our solution attempts to identify Instance #2 (the one monitored by ICO) and remove Instance #1 so that only one instance remains.

  2. Identify the duplicate process

    This step is likely already accomplished by the time you start the tutorial and is likely the reason you are here in the first place. Once you identify the self service offering that is creating duplicate requests, go into its configuration settings to identify which BPD it is set to initiate. Then find that BPD in Process designer

     

    img1

  3. Create a new BPD named "Initiate Deduping"

    For the purposes of this tutorial please be sure to name items exactly as requested. This is because the process uses TWSearch to find process instances by name and variations will cause the search to come up empty. Once this process is created please add the following variables

     

    img2

  4. Create a new general system service named "Initiate Deduping Service"

    Once the service is created set the variables as follows:

     

    img3

     

    The diagram should look like the following with two script objects:

     

    img4

  5. Fillout the scripts in the service to gather information about processes that started after itself.

    Gather System Data:

    var col1 = new TWSearchColumn();
    col1.name = TWSearchColumn.ProcessInstanceColumns.ID;
    col1.type = TWSearchColumn.Types.ProcessInstance;
    var col2 = new TWSearchColumn();
    col2.name = TWSearchColumn.ProcessInstanceColumns.Status;
    col2.type = TWSearchColumn.Types.ProcessInstance;
    var col3 = new TWSearchColumn();
    col3.name = TWSearchColumn.ProcessInstanceColumns.Name;
    col3.type = TWSearchColumn.Types.ProcessInstance;
    var search = new TWSearch();
    search.columns = new Array(col1,col2,col3);
    var condition = new TWSearchCondition();
    condition.column = new TWSearchColumn();
    condition.column.name = TWSearchColumn.ProcessInstanceColumns.Status;
    condition.column.type = TWSearchColumn.Types.ProcessInstance;
    condition.operator = TWSearchCondition.Operations.Equals;
    condition.value = “Active”;
    search.conditions = new Array(condition);
    var order1 = new TWSearchOrdering();
    order1.column = col1;
    order1.order = TWSearchOrdering.Orders.Descending;
    search.orderBy = new Array(order1);
    search.organizedBy = TWSearch.OrganizeByTypes.ProcessInstance;
    var results = search.execute();
    tw.local.outi=new tw.object.listOf.Integer();
    for(var i=0;i<results.rows.length;i++)
    {
       tw.local.outi[i]=parseInt(results.rows[i].values[0]);
    }

     

    Prep System Data:

     

    tw.local.instanceList=new tw.object.listOf.ReportInstance()
    tw.local.result=0;
    tw.local.minId=tw.system.currentProcessInstanceID;
    var currentDate=(new TWDate()).formatDate(“short”);
    tw.local.currentDate=currentDate;
    tw.local.out=””;
    for(var i=tw.local.outi.listLength-1;i>=0;i–)
    {
       tw.local.instanceList[i]=new tw.object.ReportInstance();
       tw.local.instanceList[i].tasks=new tw.object.listOf.NameValuePair();
       var temp=tw.system.findProcessInstanceByID(tw.local.outi[i]);
    ¬† ¬†var temp2=temp.businessData.get(“operationContext.id”);
       if(temp.name.indexOf(tw.local.search)>=0 && temp2==tw.local.operationContext.id)
       {
          if(tw.local.outi[i]<tw.local.minId)
          {
          tw.local.minId=tw.local.outi[i];
          temp.abort();
          }
          tw.local.result++;
       }
    }

     

  6. Return to the "Initiate Deduping" BPD and pull in the new service you created (as well as adding structures as shown)

    img5

     

    Set Get Instance as follows:

    var id=tw.system.currentProcessInstance.id;
    tw.local.instanceId=parseInt(id.substring(id.indexOf(“.”)+1));

     

    Set the Timer object to wait 1 minute

     

    Set the Initiate Deduping Service data mapping to:

    img6

  7. Finally, Add the BPD (as a linked process) as the first step of the BPD you wish to deduplicate

    img7

  8. Understanding the process

    Initiate deduping is run by every process instance that’s created for the designated BPD. A TWSearch call is made that looks for all other instances of “Initiate Deduping” being run. The script then looks for any of them with the same Request Id as itself (designated by ICO) and if they have a smaller BPM instance id then itself, it knows that it is the newest process and terminates the other. Regardless of its actions it then waits at a timer block for 1 minute so that later processes have a chance to terminate it before the actual process officially starts. This is shown to leave only 1 instance remaining per ICO Request ID (found within tw.operationContext.id)

Join The Discussion