Reuse GlideRecord in Loop? How?

William Busby
Tera Guru

I'm parsing a JSON object within a workflow that is supposed to cycle through a list of CI's and add comments to each one. The JSON object is an array of ServerName, Action, and Results for 'n' number of CIs. Parsing the JSON is good, but when I loop through the list the GlideRecord works on the first CI and no others (and doesn't throw an exception). Here's what I tried first:

doProcessResponse();

function doProcessResponse() {

  workflow.scratchpad.decommLog = "Server Decommission Log\n";

  //parse JSON string to object

  var result = new global.JSON().decode(activity.output);

  for ( var i=0; i < result.length; i++) {

  var serverGr = new GlideRecord('cmdb_ci');

  serverGr.addQuery('name', result[i].Server);

  serverGr.query();

  if (serverGr.next()) {

  var logEntry = result[i].Server + " decommission action " + result[i].Action + " results " + result[i].Result;

  gs.warn("logEntry " + logEntry);

  serverGr.comments = logEntry;

  serverGr.update();

  workflow.scratchpad.decommLog += logEntry + "\n";

  }

  // destroy GlideRecord object for reuse

  serverGr = null;

  }

  gs.warn("workflow.scratchpad.decommLog = " + workflow.scratchpad.decommLog);

}

So, knowing that objects created in functions are garbage collected and subsequent calls to the function create new objects I just moved all the logic into a function like this:

doProcessResponse();

function doProcessResponse() {

  workflow.scratchpad.decommLog = "Server Decommission Log\n";

  //parse JSON string to object

  var result = new global.JSON().decode(activity.output);

  for ( var i=0; i < result.length; i++) {

  doUpdates(result[i]);

  }

  gs.warn("workflow.scratchpad.decommLog = " + workflow.scratchpad.decommLog);

}

function doUpdates(result) {

  var serverGr = new GlideRecord('cmdb_ci');

  serverGr.addQuery('name', result.Server);

  serverGr.query();

  if (serverGr.next()) {

  var logEntry = result.Server + " decommission action " + result.Action + " results " + result.Result;

  gs.warn("logEntry " + logEntry);

  serverGr.comments = logEntry;

  serverGr.update();

  workflow.scratchpad.decommLog += logEntry + "\n";

  }

}

WTF??? Again only the first result object is processed!!!

1 ACCEPTED SOLUTION

William Busby
Tera Guru

Apologies to everyone who tried to help with this but the pain was entirely self-inflicted. Turns out the JSON object had a space char prepended to the server name EXCEPT for the first one. That extra space was causing the query to fail. Once I removed whitespace all is well. Yet another lesson in making assumptions.


View solution in original post

16 REPLIES 16

This script should work for you:



(function(){


  var workflow.scratchpad.decommLog = "Server Decommission Log\n";


  //parse JSON string to object


  var result = JSON.parse(activity.output);



  //loop through the results


  for ( var i=0; i < result.length; i++) {


      var serverGr = new GlideRecord('cmdb_ci');


      serverGr.addQuery('name', result[i].Server);


      serverGr.query();


      if (serverGr.next()) {


          var logEntry = result[i].Server + " decommission action " + result[i].Action + " results " + result[i].Result;


          gs.warn("logEntry " + logEntry);


          serverGr.comments = logEntry;


          serverGr.update();


          workflow.scratchpad.decommLog += logEntry + "\n";


      }


  }


  gs.warn("workflow.scratchpad.decommLog = " + workflow.scratchpad.decommLog);


})();



I replaced "global.JSON().decode" on line 4 with "JSON.parse" and that seems to fix everything.   I created 4 servers with your names and passed in a JSON object with your data and they were all updated.   I've read that using "parse" is the safer way to go as well.


No Joy. I pasted your script verbatim (had to remove the 'var' in front of line 2) as shown below.



(function(){  


  workflow.scratchpad.decommLog = "Server Decommission Log\n";  


  //parse JSON string to object  


  var result = JSON.parse(activity.output);  


  gs.log(JSUtil.logObject(result));


 


  //loop through the results  


  for ( var i=0; i < result.length; i++) {  


      var serverGr = new GlideRecord('cmdb_ci');  


      serverGr.addQuery('name', result[i].Server);  


      serverGr.query();  


      if (serverGr.next()) {  


          var logEntry = result[i].Server + " decommission action " + result[i].Action + " results " + result[i].Result;  


          gs.warn("logEntry " + logEntry);  


          serverGr.comments = logEntry;  


          serverGr.update();  


          workflow.scratchpad.decommLog += logEntry + "\n";  


      }  


  }  


  gs.warn("workflow.scratchpad.decommLog = " + workflow.scratchpad.decommLog);  


})();



And the logs captured the object looking very much the same as using new global.JSON().decode(activity.output); with only the first CI being processed. Can you tell me how to replicate your testing - possibly I can gleam something to dig into?



Log Object


Array of 3 elements


[0]: Object


Result: string = Success


Server: string = ACAP0116


Action: string = DecommissioningStatusACSI.ps1


[1]: Object


Result: string = Success


Server: string = ACAP0126


Action: string = DecommissioningStatusACSI.ps1


[2]: Object


Result: string = Success


Server: string = ACAP0130


Action: string = DecommissioningStatusACSI.ps1



logEntry ACAP0116 decommission action DecommissioningStatusACSI.ps1 results Success



workflow.scratchpad.decommLog = Server Decommission Log


ACAP0116 decommission action DecommissioningStatusACSI.ps1 results Success


Long shot at this point but could you try:


serverGr.addQuery('name', result[i].Server+'');



This doesn't change the value but forces JavaScript to change the data type


I tried both that and 'toString()' with no change in behavior. Really appreciate the replies all - just a bit frustrating to have to work on what should be a very, very simple process.


I knew I was going to miss removing something in the script - I had to use a variable instead of the workflow scratchpad.   After creating 4 CI records with the ACAT names in your data set, this is what I used to simulate your scenario, running it in the Xplore: Developer Toolkit (or a Background Script):



var testData = [{ "Result" : "Success", "Server" : "ACAT1442", "Action" : "DecommissioningStatusACSI.ps1" }, { "Result" : "Success", "Server" : "ACAT1445", "Action" : "DecommissioningStatusACSI.ps1" }, { "Result" : "Success", "Server" : "ACAT1463", "Action" : "DecommissioningStatusACSI.ps1" }, { "Result" : "Success", "Server" : "ACAT1466", "Action" : "DecommissioningStatusACSI.ps1" }];


var testJsonData = JSON.stringify(testData);



(function(parm1){


  var decommLog = "Server Decommission Log\n";


  //parse JSON string to object


  var result = JSON.parse(parm1);



  //loop through the results


  for ( var i=0; i < result.length; i++) {


      var serverGr = new GlideRecord('cmdb_ci');


      serverGr.addQuery('name', result[i].Server);


      serverGr.query();


      if (serverGr.next()) {


          var logEntry = result[i].Server + " decommission action " + result[i].Action + " results " + result[i].Result;


          gs.warn("logEntry " + logEntry);


          serverGr.comments = logEntry;


          serverGr.update();


          decommLog += logEntry + "\n";


      }


  }


  gs.warn("decommLog = " + decommLog);



})(testJsonData);



The comments field is updated each time for each of the servers.   The first two lines are just for creating the JSON data and I pass it into the function on line 24.



My data seems to end up looking just like yours:


Log Object


Array of 4 elements


[0]: Object


Result: string = Success


Server: string = ACAT1442


Action: string = DecommissioningStatusACSI.ps1


[1]: Object


Result: string = Success


Server: string = ACAT1445


Action: string = DecommissioningStatusACSI.ps1


[2]: Object


Result: string = Success


Server: string = ACAT1463


Action: string = DecommissioningStatusACSI.ps1


[3]: Object


Result: string = Success


Server: string = ACAT1466


Action: string = DecommissioningStatusACSI.ps1