I have the following ServiceNow script which inserts the record into 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);
But after inserting the record it again goes back to the try block again and does the whole thing again and now with the inserted record
How is this business rule configured? Is it possible that the changes made by this script, could also trigger the script to run?
Here's an example of what I mean: Imagine I have a business rule that executes whenever a record in the table "u_arbitrary_counter" is updated. Imagine that the function of this business rule is that whenever such a record is updated, we increase the value of the "u_counter" field by one, like so:
current.setValue('u_counter', parseInt(current.getValue('u_counter')) + 1);
current.update();
By using .update()
, I'm forcing an update to the database, EVEN if this is a "before" business rule.
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.
So using current.update() in a BEFORE business rule isn't a great idea. For the same reason though, performing any other operation which necessarily leads to a database update which could trigger this same business rule is a bad idea. It doesn't have to be current.update()
-- Instead, imagine if rather than updating the current record, I did something like...
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!
This is no good for the same reason. Ditto for any REST calls which would trigger a DB action on this table which may trigger this business rule.
If this is indeed the cause of your issue (and without knowing the configuration of your business rule, I can't be sure if it is or not), there is actually a way to tell the system not to run any further business rules as a result of the operation your script performs. Right before your gr.insertWithReferences();
line (line 91), IF that block of code is the issue (which I'm fairly confident it is), add:
gr.setWorkflow(false);
This prevents business rules from running. Unfortunately, since you're placing the record into the live_message table, that may not be a good idea either, since the messenger may require some business rule to propagate or present that information once inserted; I'm not sure. If that is the case, I would recommend adding a condition to your business rule so that it only runs under certain circumstances, and then craft your inserted record to not meet those criteria.
Pro Tip: PS - I notice you access a table field using
current.field_name.toString()
in some places, and directly accesscurrent.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.