Workaround For GlideRecord SetWorkflow(false) Issue

As part of the GlideRecord API comes the function setWorkflow(false) .

If you’ve never used this before, essentially this function switches off the running of any subsequent business rules or workflows. This is really useful in a number of scenarios, for example when you need to update a lot of records in bulk and do not want emails to be automatically sent out for each one.

I’ve been recently working on archiving and using the OOB implementation was just too slow for us (OOB was taking approximately 5 minutes to archive one incident and 5 tasks, my custom one now archive 150 incidents, 500 tasks, all audit records, journal records, attachments etc, in less than a minute).

But while doing this, I needed to delete records from one place in ServiceNow and put them somewhere else. I didn’t want it audited that I deleted these records nor did I want business rules being triggered on the back of the deletions. So away I went setting setWorkflow(false) when deleting everything but this is where I stumbled across an issue… the business rules still ran, as did auditing!!

So I decided to dig a bit further, and I discovered that setWorkflow(false) doesn’t ALWAYS switch off business rules. Let me explain….

Create a simple business rule on the task table which runs on delete:

gs.print(current.sys_id + ' was deleted from table: ' + current.sys_class_name);

So let’s give it a quick go to make sure everything is going to plan so far. Run the below as a background script:

//Create a new record on the task table and a new one on the incident table
var gt = new GlideRecord('task');
gt.initialize();
gt.short_description = 'task record';
var t = gt.insert();

var gi = new GlideRecord('incident');
gi.initialize();
gi.short_description = 'incident record';
var i = gi.insert();

//Now we delete them

var gr = new GlideRecord('task');
gr.addQuery('sys_id', 'IN', t + ',' + i);
gr.deleteMultiple();

The result is unsurprising. There are two statements printed out (when you do it obviously sys_ids will be different):

*** Script: 2b69d0c36fd6110070ec91cdbb3ee4ff was deleted from table: incident
*** Script: a369d0c36fd6110070ec91cdbb3ee4ff was deleted from table: task

So now do the same thing again, except before the deleteMultiple() statement, we will setWorkflow as false:

//Create a new record on the task table and a new one on the incident table
var gt = new GlideRecord('task');
gt.initialize();
gt.short_description = 'task record';
var t = gt.insert();

var gi = new GlideRecord('incident');
gi.initialize();
gi.short_description = 'incident record';
var i = gi.insert();

//Now we delete them

var gr = new GlideRecord('task');
gr.addQuery('sys_id', 'IN', t + ',' + i);
gr.setWorkflow(false);
gr.deleteMultiple();

The expectation here is no business rules should run and so there should be no statements. What actually prints out is this:

*** Script: 644a54076fd6110070ec91cdbb3ee43b was deleted from table: incident

So what went wrong? Turns out, setWorkflow(false) when deleting is not carried through to all extended tables. i.e. if the GlideRecord is run on the task table, any deletions directly on the task table will not run business rules, but any deletions that occur on the extension tables (such as incident above) will run business rules!

This took me a lot of head scratching to figure out and when I came up with the above conclusion, was confirmed by ServiceNow.

The next step I had then was to figure out a workaround. This is what I came up with.

First create a function. You can put this in a script include later to be called from anywhere:

function deleteWorkflowFalse( /* GlideRecord */ gr) {

  //Find all the extensions for the table for the GlideRecord (including base table)
  var table = gr.getTableName();
  var tu = new TableUtils(table);
  var ext = tu.getAllExtensions();
  var tableQ;
  //Get the query from the GlideRecord
  var query = gr.getEncodedQuery();
  var t;

  //Loop through each of the extension tables
  for (var i = 0; i < ext.size(); i++) {
    t = ext.get(i);
    tableQ = new GlideRecord(t);
    tableQ.addEncodedQuery(query);
    //Ensure we only delete records which are on the base table
    tableQ.addQuery('sys_class_name', t);
      tableQ.setWorkflow(false);
      tableQ.deleteMultiple();
    }
  }

A short explanation is that this script gets the base table and all the extension table for the base table. Then it loops through each one and does a separate glide record on each extension table and deletes all records which specifically sit on that table. Doing it this way, means that we’re not exposed to the issue of deleting records not on the same table as the glide record.

Now let’s use this function in the first script that we tested and see if it works as planned:

//Create a new record on the task table and a new one on the incident table
var gt = new GlideRecord('task');
gt.initialize();
gt.short_description = 'task record';
var t = gt.insert();

var gi = new GlideRecord('incident');
gi.initialize();
gi.short_description = 'incident record';
var i = gi.insert();

//Now we delete them

var gr = new GlideRecord('task');
gr.addQuery('sys_id', 'IN', t + ',' + i);
gr.setWorkflow(false);
deleteWorkflowFalse(gr);

Low and behold, no messages were printed! Sorry for the very long post to what essentially is quite a simple solution, but wanted to make sure it was clear what was happening 🙂

If you have any questions, just pop them in the comments.

1 Comment

  1. Reblogged this on EcoStratus Technologies @14 Emerton and commented:
    Thanks for sharing Ahmed. Excellent info.
    Ahmed wrote: “As part of the GlideRecord API comes the function setWorkflow(false) .

    If you’ve never used this before, essentially this function switches off the running of any subsequent business rules or workflows. This is really useful in a number of scenarios, for example when you need to update a lot of records in bulk and do not want emails to be automatically sent out for each one. ”

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s