Servicenow脚本无限递归

Servicenow script infinite recursion

我有以下 ServiceNow 脚本,它将记录插入 live_message table。

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


  var requestBody;
  var responseBody;
  var status;
  var request;
  var response;

  try {

    request = new sn_ws.RESTMessageV2("LiveMessageWebhook", "post");

    request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");


    var parameters = "&chat_message=" + current.chat_message.toString();
    parameters = parameters + "&context=" + current.context.toString();
    parameters = parameters + "&formatted_message=" + current.formatted_message.toString();
    parameters = parameters + "&has_attachments=" + current.has_attachments.toString();
    parameters = parameters + "&has_links=" + current.has_links.toString();
    parameters = parameters + "&has_tags=" + current.has_tags.toString();
    parameters = parameters + "&ID=" + current.id.toString();
    parameters = parameters + "&in_reply_to=" + current.in_reply_to.toString();
    parameters = parameters + "&isLiked=" + current.is_liked.toString();
    parameters = parameters + "&lastActivity=" + current.last_activity.toString();
    parameters = parameters + "&lastMessage=" + current.last_message.toString();
    parameters = parameters + "&likeCount=" + current.like_count.toString();
    parameters = parameters + "&message=" + current.message.toString();
    parameters = parameters + "&next_reply_order_chunk=" + current.next_reply_order_chunk.toString();
    parameters = parameters + "&order=" + current.order.toString();
    parameters = parameters + "&poll=" + current.poll.toString();
    parameters = parameters + "&private=" + current.private_message.toString();
    parameters = parameters + "&profile=" + current.profile.toString();
    parameters = parameters + "&reflected_field=" + current.reflected_field.toString();
    parameters = parameters + "&reply_to=" + current.reply_to.toString();
    parameters = parameters + "&state=" + current.state.toString();
    parameters = parameters + "&group_type=" + current.sys_class_name.toString();
    parameters = parameters + "&created_by=" + current.sys_created_by.toString();
    parameters = parameters + "&created_on=" + current.sys_created_on.toString();
    parameters = parameters + "&domain=" + current.sys_domain.toString();
    parameters = parameters + "&domain_path=" + current.sys_domain_path.toString();
    parameters = parameters + "&sys_ID=" + current.sys_id.toString();
    parameters = parameters + "&to_profile=" + current.sys_domain.toString();
    parameters = parameters + "&updates=" + current.sys_mod_count.toString();
    parameters = parameters + "&updated_by=" + current.sys_updated_by.toString();
    parameters = parameters + "&updated_on=" + current.sys_updated_on.toString();

    request.setRequestBody(encodeURI(parameters));
    var l = request.getRequestBody();
    response = request.execute();

    responseBody = response.haveError()
      ? response.getErrorMessage()
      : response.getBody();
    status = response.getStatusCode();
    {
      var gr = new GlideRecord('live_message');

      gr.initialize();
      gr.chat_message = current.chat_message;
      gr.context = current.context.toString();
      gr.formatted_message = "abc";
      gr.group = current.group;
      gr.has_attachments = current.has_attachments;
      gr.has_links = current.has_links;
      gr.has_tags = current.has_tags;
      gr.id = current.id;
      gr.in_reply_to = "admin";
      gr.is_liked = current.is_liked;
      gr.last_activity = current.last_activity;
      gr.last_message = current.last_message;
      gr.like_count = current.like_count;
      gr.message = "abc";
      gr.next_reply_order_chunk = current.next_reply_order_chunk;
      gr.order = current.order;
      gr.poll = current.poll;
      gr.private_message = current.private_message;
      gr.profile = current.profile;
      gr.reflected_field = current.reflected_field;
      gr.reply_to = current.reply_to;
      gr.state = current.state;

      gr.sys_class_name = current.sys_class_name;
      gr.sys_created_by = current.sys_created_by;
      gr.sys_created_on = current.sys_created_on;
      gr.sys_domain = current.sys_domain;
      gr.sys_domain_path = current.sys_domain_path;
      gr.sys_mod_count = current.sys_mod_count;
      gr.sys_updated_by = current.sys_updated_by;
      gr.sys_updated_on = current.sys_updated_on;
      gr.to_profile = current.to_profile;
      gr.insertWithReferences();

    }

  } catch (ex) {
    responseBody = 'Exception: ' + ex;
    status = '900';
    requestBody = request
      ? request.getRequestBody()
      : null;
  } finally {
    gs.info("Final: Request Body: " + requestBody);
    gs.info("Final: Response: " + responseBody);
    gs.info("Final: HTTP Status: " + status);
    gs.addInfoMessage('Final: Finished');
  }

})(current, previous);

但是在插入记录后,它再次返回到 try 块并再次执行整个操作,现在使用插入的记录

这个业务规则是如何配置的? 此脚本所做的更改是否也可能触发脚本到运行?

这是我的意思的一个例子: 假设我有一个业务规则,每当 table "u_arbitrary_counter" 中的记录更新时执行。 想象一下,这个业务规则的功能是每当更新这样的记录时,我们将 "u_counter" 字段的值增加一,就像这样:

current.setValue('u_counter', parseInt(current.getValue('u_counter')) + 1);
current.update();

通过使用 .update(),我强制更新数据库,即使这是 "before" 业务规则。

Pro Tip: Note that "before" business rules run on the data that's about to be saved to the database, BEFORE the actual database operation has taken place. Any changes to the "current" object in a "before" business rule will be saved even without using current.update, because you're modifying the data that's about to be sent to the database anyway, in the natural course of this operation.

因此,在 BEFORE 业务规则中使用 current.update() 并不是一个好主意。但出于同样的原因,执行任何其他必然导致数据库更新并可能触发相同业务规则的操作并不是一个好主意。它不一定是 current.update() -- 相反,想象一下,如果我没有更新当前记录,而是做了类似...

var gr = new GlideRecord('u_arbitrary_counter'); //the same table this BR is running on
gr.initialize();
gr.setValue('u_counter', parseInt(current.getValue('u_counter')) + 1);
gr.insert(); //This triggers a database action!

出于同样的原因,这也不好。 同上任何 REST 调用都会触发对此 table 的数据库操作,这可能会触发此业务规则。


解决方案

如果这确实是你问题的原因(并且不知道你的业务规则的配置,我不能确定是否是),实际上有一种方法可以告诉系统不要运行 作为脚本执行操作的结果的任何进一步的业务规则。在您的 gr.insertWithReferences(); 行(第 91 行)之前,如果该代码块是问题所在(我相当有信心),请添加:

gr.setWorkflow(false);

这会阻止业务规则 运行ning。 不幸的是,由于您将记录放入 live_message table,因此 可能 也不是一个好主意,因为信使可能需要一些业务规则来传播或呈现该信息,一旦插入;我不确定。 如果是这种情况,我建议在您的业务规则中添加一个条件,使其在某些情况下仅 运行s,然后将您插入的记录制作成 满足这些条件标准。

Pro Tip: PS - I notice you access a table field using current.field_name.toString() in some places, and directly access current.field_name in others. While the former is acceptable (not that I recommend it in most cases), the latter should almost never be used -- except in the case of journal fields. Instead, I strongly recommend using the appropriate getter/setter methods, to avoid pass-by-reference issues and confusion, and to ensure you're not relying on JavaScript's coersion, which doesn't always play nice with Mozilla Rhino, which ServiceNow runs on the back-end. Example issue here. For more info, please see my article on using getValue() and setValue() in ServiceNow.