Gauge Data Visualization UI Builder loads too slow

Hari1
Mega Sage

Hi,

I have added the Gauge Data Visualization component in UI builder which is taking long time to load (25~30 Seconds) when i preview it. 

Below is the customization that i have done in UI Builder

Hari1_0-1737117802598.png

/**
  * @Param {params} params
  * @Param {api} params.api
  * @Param {TransformApiHelpers} params.helpers
  */
function evaluateProperty({api, helpers}) {
	var data = [{
        "data": [{
            "value": api.data.cmdb_ci_governance_server_1.output.Coverage[0].Percentage,
            "change": "0",
            "changePercent": "0"
        }],
        "metadata": {
            "eventData": {
                "indicatorSysid": ""
            },
            "dataSourceLabel": "",
            "filterQuery": "",
            "aggregate": {
                "fieldType": "decimal"
            },
            "format": {
                "unitFormat": "{0}",
                "frequency": "daily",
                "precision": 0
            }
        }
        
    }];
    return data;
}

Data Resource - Transform:

[
{
    "name": "ciType",
    "label": "CI Type",
    "description": "Type of the CI",
    "readOnly": "false",
    "fieldType": "string",
    "mandatory": true,
    "defaultValue": ""
},
{
    "name": "usedByOrg",
    "label": "Used By Org",
    "description": "Used By Org",
    "readOnly": "false",
    "fieldType": "string",
    "mandatory": true,
    "defaultValue": ""
}
]

Script:

function transform(input) {

	var start = new Date().getTime();

    var usedByOrgVal = input.usedByOrg;
    var arrFinCount = [];

    if (usedByOrgVal == "All") {
        arrFinCount = [filterList("operational_status!=6"), filterList("operational_status!=6^owned_by!=null"), filterList("operational_status!=6^u_in_coverage=Yes"), filterList("operational_status!=6^u_complete=Yes"), filterList("operational_status!=6^u_correct=Yes", "operational_status!=6^u_in_coverage=No"), filterList("operational_status!=6^u_complete=No"), filterList("operational_status!=6^u_correct=No"), filterList("nameISNOTEMPTY^operational_status!=6^u_resp_orgISNOTEMPTY^NQnameISNOTEMPTY^operational_status!=6^u_resp_orgISEMPTY^assetISEMPTY")];
    } else {
        arrFinCount = [filterList("operational_status!=6^owned_by.u_program=" + usedByOrgVal), filterList("operational_status!=6^owned_by!=null^owned_by.u_program=" + usedByOrgVal), filterList("operational_status!=6^u_in_coverage=Yes^owned_by.u_program=" + usedByOrgVal), filterList("operational_status!=6^u_complete=Yes^owned_by.u_program=" + usedByOrgVal), filterList("operational_status!=6^u_correct=Yes^owned_by.u_program=" + usedByOrgVal), filterList("operational_status!=6^u_in_coverage=No^owned_by.u_program=" + usedByOrgVal), filterList("operational_status!=6^u_complete=No^owned_by.u_program=" + usedByOrgVal), filterList("operational_status!=6^u_correct=No^owned_by.u_program=" + usedByOrgVal), filterList("nameISNOTEMPTY^operational_status!=6^u_resp_orgISNOTEMPTY^NQnameISNOTEMPTY^operational_status!=6^u_resp_orgISEMPTY^assetISEMPTY^owned_by.u_program=" + usedByOrgVal)];
    }

    function filterList(arrVal) {
        var cal = new GlideRecord("cmdb_ci_server");
        cal.addEncodedQuery(arrVal);
        cal.query();
        return cal.getRowCount();
    }

    var obj = {
        Ownership: [{
            Value: arrFinCount[1],
            Percentage: isNaN(((arrFinCount[1] / arrFinCount[0]) * 100).toFixed(2)) ? "0.00" : ((arrFinCount[1] / arrFinCount[0]) * 100).toFixed(2),
        }],
        Coverage: [{
            InCoverage: arrFinCount[2],
            OutOfCoverage: arrFinCount[5],
            Percentage: isNaN(((arrFinCount[2] / arrFinCount[0]) * 100).toFixed(2)) ? "0.00" : ((arrFinCount[2] / arrFinCount[0]) * 100).toFixed(2),
        }],
        Completeness: [{
            Complete: arrFinCount[3],
            NotComplete: arrFinCount[6],
            Percentage: isNaN(((arrFinCount[3] / arrFinCount[0]) * 100).toFixed(2)) ? "0.00" : ((arrFinCount[3] / arrFinCount[0]) * 100).toFixed(2),
        }],
        Correctness: [{
            Correct: arrFinCount[4],
            NotCorrect: arrFinCount[7],
            Percentage: isNaN(((arrFinCount[4] / arrFinCount[0]) * 100).toFixed(2)) ? "0.00" : ((arrFinCount[4] / arrFinCount[0]) * 100).toFixed(2),
        }],
        ActiveServerCount: [{
            Count: arrFinCount[8]
        }],
    };

    var end = new Date().getTime();
    var time = end - start;

    gs.info('CMDB: Execution time Server: ' + time);

    return obj;
}

 

1 ACCEPTED SOLUTION

1. create new field on table of type JSON

2. read how to create scheduled job (https://www.servicenow.com/docs/bundle/xanadu-platform-administration/page/administer/reference-page...)

3. store the response object from the script into that JSON field within scheduled job

4. on page load query that field, parse the response and use it in your compoentns

View solution in original post

20 REPLIES 20

Well its hard to debug without actuall data. 

make sure that your DR is executed only once, also how many records are in that table?

Here's updated function that should work properly:

 

function transform(input) {
  var start = new Date().getTime();

  var usedByOrgVal = input.usedByOrg;
  var arrFinCount = [];

  // Arrays to preserve order
  var ifQueries = getIfQueries();
  var elseQueries = getElseQueries();

  if (usedByOrgVal == "All") {
    arrFinCount = filterList(ifQueries);
  } else {
    arrFinCount = filterList(elseQueries.map((query) => query + usedByOrgVal));
  }

  function filterList(queryArr) {
    return queryArr.map((query) => {
      var cal = new GlideAggregate("cmdb_ci_server");
      cal.addAggregate("COUNT");
      cal.addEncodedQuery(query);
      cal.query();

      let count;

      while (cal.next()) {
        count = cal.getAggregate("COUNT");
      }
      return count;
    });
  }

  var obj = {
    Ownership: createMetric(arrFinCount[1], arrFinCount[0]),
    Coverage: createCoverageMetrics(
      arrFinCount[2],
      arrFinCount[5],
      arrFinCount[0]
    ),
    Completeness: createMetric(arrFinCount[3], arrFinCount[0]),
    Correctness: createMetric(arrFinCount[4], arrFinCount[0]),
    ActiveServerCount: [{ Count: arrFinCount[8] }],
  };

  var end = new Date().getTime();
  var time = end - start;

  gs.info("CMDB: Execution time Server: " + time);

  return obj;

  // Helper functions
  function createMetric(count, total) {
    return [
      {
        Value: count,
        Percentage: isNaN(((count / total) * 100).toFixed(2))
          ? "0.00"
          : ((count / total) * 100).toFixed(2),
      },
    ];
  }

  function createCoverageMetrics(inCoverage, outOfCoverage, total) {
    return [
      {
        InCoverage: inCoverage,
        OutOfCoverage: outOfCoverage,
        Percentage: isNaN(((inCoverage / total) * 100).toFixed(2))
          ? "0.00"
          : ((inCoverage / total) * 100).toFixed(2),
      },
    ];
  }

  function getIfQueries() {
    return [
      "operational_status!=6",
      "operational_status!=6^owned_by!=null",
      "operational_status!=6^u_in_coverage=Yes",
      "operational_status!=6^u_complete=Yes",
      "operational_status!=6^u_correct=Yes",
      "operational_status!=6^u_in_coverage=No",
      "operational_status!=6^u_complete=No",
      "operational_status!=6^u_correct=No",
      "nameISNOTEMPTY^operational_status!=6^u_resp_orgISNOTEMPTY^NQnameISNOTEMPTY^operational_status!=6^u_resp_orgISEMPTY^assetISEMPTY",
    ];
  }

  function getElseQueries() {
    return [
      "operational_status!=6^owned_by.u_program=",
      "operational_status!=6^owned_by!=null^owned_by.u_program=",
      "operational_status!=6^u_in_coverage=Yes^owned_by.u_program=",
      "operational_status!=6^u_complete=Yes^owned_by.u_program=",
      "operational_status!=6^u_correct=Yes^owned_by.u_program=",
      "operational_status!=6^u_in_coverage=No^owned_by.u_program=",
      "operational_status!=6^u_complete=No^owned_by.u_program=",
      "operational_status!=6^u_correct=No^owned_by.u_program=",
      "nameISNOTEMPTY^operational_status!=6^u_resp_orgISNOTEMPTY^NQnameISNOTEMPTY^operational_status!=6^u_resp_orgISEMPTY^assetISEMPTY^owned_by.u_program=",
    ];
  }
}

Hi @IronPotato , I can see the values in the output object. But the execution time is now 11 seconds.

For your question "make sure that your DR is executed only once, also how many records are in that table?"
The data resource "When to evaluate this data resource" is set to "Immediately" as i need to data resource to run on page load and when the dropdown option is selected. For each query run from the script it returns a 80-50 thousand record count. The table total count is of 3,18,387 records.

Hari1_0-1737183441649.png

 

TBH that 11s is good number considering the computation that needs to happen. Also it was reduced from 30s to 11s. So thats a good start. The ammount of records are not small.

 

Also take into account sevicenow instance server response.

 

So my next question is, whether you need all the queries to be executed from array if dropdown is selected?

Yes, All the queries needs to be executed when the dropdown is selected. as i need to display the response object values in the data visualization and the labels. 

When i try the same query in the UI Builder it takes longer 15~20 seconds in the background script it takes 11 seconds