How would I prevent a Business Rule from running twice?

Shant Cancik
Tera Contributor

I have two Business Rules set up.

One business rule is on the sc_req_item table and copies comments on the RITM record as work Notes on the Task record.

Table: sc_req_item

Runs on: After

Condition: current.comments.changes()

The second business rule is on the sc_task table and copies comments on the Task record to comments on the RITM record.

Table: sc_task

Runs on: After

Condition: current.comments.changes()

This is working fine for the most part. If a user comments on the RITM, the first business rule runs and copies that comment as a work note to the Task record. When a fulfiller eventually types a comment on this Task record, that comment gets sent over to the RITM record as a RITM comment. This is great and the functionality I want.

My problem is that when this second business rule runs and updates the RITM record, my first business rule gets triggered because its condition is waiting for that field to change. This leads to duplicate text on my Task record.   I've been trying to fix this but am getting nowhere. Anyone have an idea of what I can do about this?

1 ACCEPTED SOLUTION

Brian Dailey1
Kilo Sage

Hi Shant,



You can place a global variable in your business rule to indicate where the update originated (i.e., from which task).   This variable will persist only while that particular update is being processed.   For example...



For your Business Rule on [sc_task]:


var updateInitiatedBy = updateInitiatedBy || current.sys_id.toString();



(function executeRule(current, previous /*null when async*/) {


      if(updateInitiatedBy == current.sys_id.toString()){


              var gr = new GlideRecord('sc_req_item');


              gr.addQuery('sys_id',current.request_item.sys_id.toString());


              gr.query();


              while(gr.next()){


                      gr.comments = current.comments;


                      gr.update();


              }


      }


})(current, previous);




For your Business Rule on [sc_req_item]:


var updateInitiatedBy = updateInitiatedBy || current.sys_id.toString();



(function executeRule(current, previous /*null when async*/) {


      if(updateInitiatedBy == current.sys_id.toString()){


              var gr = new GlideRecord('sc_task');


              gr.addQuery('request_item',current.sys_id);


              gr.query();


              while(gr.next()){


                      gr.comments = current.comments;


                      gr.update();


              }


      }


})(current, previous);




Only the rule which fires initially and sets the variable 'updateInitiatedBy' will initiate a GlideRecord and update the other RITM or TASK record associated with its 'current' record.   Also, it is important to make these run as 'Before' business rules (I believe) because you are dealing with Journal Entry fields which will no longer contain a value after the update has been committed to the database.



Give that a try and let me know if you have any questions.




Thanks,


-Brian





Edit:   I changed the global variable's name to 'updateInitiatedBy' for the sake of code clarity.


View solution in original post

15 REPLIES 15

Pradeep Sharma
ServiceNow Employee
ServiceNow Employee

Hello Shant,



Modify the first BR condition as current.comments.changes() && gs.isInteractive()


Thanks for the tip Pradeep but unfortunately this did not work.



I tried setting my first business rule condition to current.comments.changes() && gs.isInteractive()


I also tried current.comments.changes() && gs.getSession().isInteractive()




Both tests showed me the same behavior I was originally having. The 1st business rule still runs when I add a comment on the RITM and the second business rule triggered by a comment on my TASK updates the RITM comments and forces the business rule to run again, leaving me with 2 fields of identical text ever time I add a comment to a Task



Any ideas ?



I also tried setting my condition to !gs.interactive() but this prevented my 1st business rule from running all together 😕


We do something similar to what you're doing, however we check if the RITM is being updated by the assigned to of the SCTask. If they are the same, we don't push the comments back to the SCTask. Script below is what we use on the RITM:



var ritmupdater = gs.getUserID();


     


      var gr = new GlideRecord('sc_task');


      gr.addQuery('request_item',current.sys_id);


      gr.query();


      while(gr.next()){


              //if RITM is updated by SCTASK assigned to, don't push comments to work notes


              if (gr.assigned_to != ritmupdater)


                      gr.work_notes = current.comments;


              gr.update();


      }


Brian Dailey1
Kilo Sage

Hi Shant,



You can place a global variable in your business rule to indicate where the update originated (i.e., from which task).   This variable will persist only while that particular update is being processed.   For example...



For your Business Rule on [sc_task]:


var updateInitiatedBy = updateInitiatedBy || current.sys_id.toString();



(function executeRule(current, previous /*null when async*/) {


      if(updateInitiatedBy == current.sys_id.toString()){


              var gr = new GlideRecord('sc_req_item');


              gr.addQuery('sys_id',current.request_item.sys_id.toString());


              gr.query();


              while(gr.next()){


                      gr.comments = current.comments;


                      gr.update();


              }


      }


})(current, previous);




For your Business Rule on [sc_req_item]:


var updateInitiatedBy = updateInitiatedBy || current.sys_id.toString();



(function executeRule(current, previous /*null when async*/) {


      if(updateInitiatedBy == current.sys_id.toString()){


              var gr = new GlideRecord('sc_task');


              gr.addQuery('request_item',current.sys_id);


              gr.query();


              while(gr.next()){


                      gr.comments = current.comments;


                      gr.update();


              }


      }


})(current, previous);




Only the rule which fires initially and sets the variable 'updateInitiatedBy' will initiate a GlideRecord and update the other RITM or TASK record associated with its 'current' record.   Also, it is important to make these run as 'Before' business rules (I believe) because you are dealing with Journal Entry fields which will no longer contain a value after the update has been committed to the database.



Give that a try and let me know if you have any questions.




Thanks,


-Brian





Edit:   I changed the global variable's name to 'updateInitiatedBy' for the sake of code clarity.