0% found this document useful (0 votes)
24 views27 pages

ServiceNow Business Rules Guide

The ServiceNow Business Rules Learning Guide provides an overview of server-side scripts that automate record operations such as querying, updating, inserting, and deleting. It covers core concepts, execution timing, script structure, best practices, and common patterns for effective implementation. The guide also emphasizes performance optimization and testing/debugging techniques to enhance the efficiency and reliability of business rules.

Uploaded by

Sahil Shinde
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views27 pages

ServiceNow Business Rules Guide

The ServiceNow Business Rules Learning Guide provides an overview of server-side scripts that automate record operations such as querying, updating, inserting, and deleting. It covers core concepts, execution timing, script structure, best practices, and common patterns for effective implementation. The guide also emphasizes performance optimization and testing/debugging techniques to enhance the efficiency and reliability of business rules.

Uploaded by

Sahil Shinde
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

ServiceNow Business Rules - Complete

Learning Guide
Table of Contents
1. What are Business Rules?
2. Core Concepts
3. When to Execute
4. Script Structure
5. Best Practices
6. Common Patterns
7. Performance Optimization
8. Testing & Debugging
9. Advanced Topics

What are Business Rules?


Business Rules are server-side scripts that execute when records are queried, updated,
inserted, or deleted. They are the backbone of automation in ServiceNow.

Key Characteristics

 Execute on the server (not client-side)


 Run automatically based on conditions
 Can modify current record or related records
 Support both synchronous and asynchronous execution

Common Use Cases

 Data validation and enforcement


 Auto-population of fields
 Workflow automation
 Calculations and computations
 Email notifications
 Integration triggers

Core Concepts
1. The current Object

Represents the current record being processed.


// Accessing fields
var priority = [Link];
var caller = current.caller_id.getDisplayValue();

// Setting fields
current.assignment_group = 'Hardware Support';
[Link] = 2; // In Progress

// Checking if field is empty


if (current.assigned_to.nil()) {
// Field is empty
}

2. The previous Object

Represents the record before changes (only in Update operations).

// Check if state changed


if ([Link] != [Link]) {
[Link]('State changed from ' + [Link] + ' to ' +
[Link]);
}

// Null in Insert operations and async rules


if (previous) {
// Safe to use previous
}

3. GlideRecord

Used to query and manipulate database records.

// Query records
var gr = new GlideRecord('incident');
[Link]('active', true);
[Link]('priority', 1);
[Link]();

while ([Link]()) {
// Process each record
[Link]('Incident: ' + [Link]);
}

// Get single record


var user = new GlideRecord('sys_user');
if ([Link]('user_name', 'admin')) {
[Link]('Admin email: ' + [Link]);
}

// Insert record
var task = new GlideRecord('sc_task');
[Link]();
task.short_description = 'New task';
task.assignment_group = 'Service Desk';
[Link]();

// Update record
var inc = new GlideRecord('incident');
if ([Link](incidentId)) {
[Link] = 6;
inc.close_notes = 'Resolved';
[Link]();
}

4. GlideSystem (gs)

Global utility object for system functions.

// User information
var currentUser = [Link]();
var userName = [Link]();
var userDisplayName = [Link]();

// Messages
[Link]('Success!');
[Link]('Error occurred');

// Date/Time
var now = [Link]();
var yesterday = [Link](1);
var lastWeek = [Link](1);

// Properties
var maxAttachments = [Link]('[Link]', '10');

// Logging
[Link]('Information log');
[Link]('Warning log');
[Link]('Error log');
[Link]('Debug log');

// Date difference
var diff = [Link](startDate, endDate, true); // in seconds

When to Execute
Timing Options

When Description Use Cases current previous


Before database Validation, set field values, Yes (update
before Yes
operation prevent save only)
After database Notifications, related records, Yes (update
after Yes
operation workflows only)
Asynchronous
async Heavy processing, external calls Yes No
(queued)
display When form loads Display-only logic (rarely used) Yes No

Operation Checkboxes
☑ insert - When new record is created
☑ update - When existing record is modified
☐ delete - When record is deleted
☐ query - When record is queried (use sparingly!)

Execution Flow Example


// BEFORE rules run first
// - Validate data
// - Set calculated fields
// - Prevent save if needed

// DATABASE OPERATION occurs

// AFTER rules run next


// - Trigger workflows
// - Send notifications
// - Update related records

// ASYNC rules run in background


// - Heavy computations
// - External API calls

Script Structure
Basic Template
(function executeRule(current, previous /*null when async*/) {

// Your business logic here

})(current, previous);

Before Insert Example


(function executeRule(current, previous) {

// Auto-assign based on category


if ([Link] == 'hardware') {
current.assignment_group.setValue('Hardware Support');
} else if ([Link] == 'software') {
current.assignment_group.setValue('Software Support');
}

// Set default priority if empty


if ([Link]()) {
[Link] = 4;
}

})(current, previous);

Before Update with Validation


(function executeRule(current, previous) {

// Prevent closing without resolution notes


if ([Link] == 7 && current.close_notes == '') {
[Link]('Close notes are required');
[Link]('Cannot close without notes');
[Link](true);
}

// Prevent priority decrease on high-impact incidents


if ([Link] == 1 && [Link] > [Link]) {
[Link]('Cannot decrease priority on high-impact
incidents');
[Link] = [Link];
}

})(current, previous);

After Update with Notifications


(function executeRule(current, previous) {

// Notify when state changes to resolved


if ([Link] == 6 && [Link] != 6) {

[Link]('[Link]', current, current.caller_id,


current.assignment_group);

// Add comment
[Link] = 'Incident resolved. User notified via email.';
[Link](); // Safe in after rules
}

})(current, previous);

Async Example
(function executeRule(current, previous) {

// Heavy operation - run asynchronously

// Call external API


try {
var request = new sn_ws.RESTMessageV2();
[Link]('[Link]
[Link]('POST');
[Link]([Link]({
incident: [Link](),
description: current.short_description.toString()
}));

var response = [Link]();


var responseBody = [Link]();

// Update incident with response


var inc = new GlideRecord('incident');
if ([Link](current.sys_id)) {
inc.work_notes = 'API Response: ' + responseBody;
[Link]();
}

} catch (ex) {
[Link]('API call failed: ' + [Link]);
}

})(current, previous);

Best Practices
1. Use Conditions to Limit Execution

Condition Builder:

Priority is 1
AND State is New

Advanced Condition:

[Link]() == 'insert' ||
([Link]() && [Link] <= 2)

2. Avoid Recursive Updates


// ❌ BAD - Can cause infinite loop
(function executeRule(current, previous) {
[Link] = 1;
[Link](); // This triggers the rule again!
})(current, previous);

// ✅ GOOD - Use before rules for field changes


(function executeRule(current, previous) {
[Link] = 1;
// No update() needed - changes saved automatically
})(current, previous);

// ✅ GOOD - Check if already updated


(function executeRule(current, previous) {
if (!current.u_already_processed) {
current.u_already_processed = true;
// Do processing
[Link]();
}
})(current, previous);

3. Order Matters

Set the Order field (100, 200, 300...) to control execution sequence.

Order 100: Validate data


Order 200: Calculate fields
Order 300: Set assignment

4. Use Script Includes for Reusable Logic


// Script Include: IncidentUtils
var IncidentUtils = [Link]();
[Link] = {
initialize: function() {
},

getAssignmentGroup: function(category) {
var mapping = {
'hardware': 'Hardware Support',
'software': 'Software Support',
'network': 'Network Operations'
};
return mapping[category] || 'Service Desk';
},

type: 'IncidentUtils'
};
// Business Rule using Script Include
(function executeRule(current, previous) {

var utils = new IncidentUtils();


var group = [Link]([Link]);
current.assignment_group.setValue(group);

})(current, previous);

5. Performance Tips
// ✅ GOOD - Query once
var gr = new GlideRecord('incident');
[Link]('assignment_group', groupId);
[Link]();
var count = [Link]();

// ❌ BAD - Query in loop


for (var i = 0; i < [Link]; i++) {
var gr = new GlideRecord('incident'); // Creates new query each time
[Link](items[i]);
}

// ✅ GOOD - Use GlideAggregate for counts


var agg = new GlideAggregate('incident');
[Link]('assignment_group', groupId);
[Link]('COUNT');
[Link]();
if ([Link]()) {
var count = [Link]('COUNT');
}

6. Error Handling
(function executeRule(current, previous) {

try {
// Risky operation
var result = performComplexCalculation(current);
current.u_calculated_value = result;

} catch (ex) {
[Link]('Business Rule Error: ' + [Link]);
[Link]('An error occurred. Please contact support.');
[Link](true);
}

})(current, previous);

Common Patterns
Pattern 1: Auto-Assignment
(function executeRule(current, previous) {

if (current.assignment_group.nil() && [Link]) {

var mapping = {
'hardware': 'Hardware Support',
'software': 'Application Support',
'network': 'Network Team',
'database': 'Database Team'
};

var group = mapping[[Link]()];

if (group) {
current.assignment_group.setDisplayValue(group);
}
}

})(current, previous);

Pattern 2: Cascade Updates


(function executeRule(current, previous) {

// When parent closes, close all child tasks


if ([Link] == 3 && [Link] != 3) {

var tasks = new GlideRecord('sc_task');


[Link]('request_item', current.sys_id);
[Link]('state', '!=', 3);
[Link]();

while ([Link]()) {
[Link] = 3;
tasks.close_notes = 'Auto-closed with parent request';
[Link]();
}
}

})(current, previous);

Pattern 3: Field Calculation


(function executeRule(current, previous) {

// Calculate total cost


var quantity = parseFloat([Link]) || 0;
var unitPrice = parseFloat(current.unit_price) || 0;
var tax = parseFloat(current.tax_rate) || 0;

var subtotal = quantity * unitPrice;


var taxAmount = subtotal * (tax / 100);
var total = subtotal + taxAmount;

[Link] = [Link](2);
current.tax_amount = [Link](2);
[Link] = [Link](2);

})(current, previous);

Pattern 4: Conditional Workflow Launch


(function executeRule(current, previous) {

// Launch approval workflow for high-value requests


var cost = parseFloat(current.estimated_cost) || 0;

if (cost > 5000 && [Link] == 'not requested') {

[Link] = 'requested';

// Trigger workflow
var workflow = new Workflow();
[Link](
'Change Approval Workflow',
current,
'insert'
);
}

})(current, previous);

Pattern 5: Duplicate Detection


(function executeRule(current, previous) {

// Check for duplicate incidents


var duplicate = new GlideRecord('incident');
[Link]('caller_id', current.caller_id);
[Link]('category', [Link]);
[Link]('state', '!=', 7); // Not closed
[Link]('sys_created_on', '>', [Link](24));
[Link]('sys_id', '!=', current.sys_id);
[Link]();

if ([Link]()) {
[Link](
'A similar incident (' + [Link] + ') already exists.
' +
'Please check before creating a new one.'
);
[Link](true);
}

})(current, previous);
Pattern 6: Escalation
(function executeRule(current, previous) {

// Auto-escalate if SLA is breaching


if (!current.due_date.nil()) {

var now = new GlideDateTime();


var due = new GlideDateTime(current.due_date);

var hoursRemaining = [Link](now, due, true) / 3600;

if (hoursRemaining < 2 && hoursRemaining > 0) {


// Approaching breach
[Link] = 1;
[Link] = [Link](1, parseInt([Link]) - 1);

[Link](
'[Link]',
current,
current.assigned_to,
current.assignment_group.manager
);
}
}

})(current, previous);

Performance Optimization
1. Use Conditions Wisely
// ❌ BAD - Rule runs on every update
// Condition: (none)
if ([Link] == 6) {
// Do something
}

// ✅ GOOD - Rule only runs when needed


// Condition: State is 6
// Business rule executes only when condition is met

2. Avoid Query Loops


// ❌ BAD
var users = ['user1', 'user2', 'user3'];
for (var i = 0; i < [Link]; i++) {
var gr = new GlideRecord('sys_user');
[Link]('user_name', users[i]); // Query per iteration
}

// ✅ GOOD
var users = ['user1', 'user2', 'user3'];
var gr = new GlideRecord('sys_user');
[Link]('user_name', 'IN', [Link](','));
[Link]();
while ([Link]()) {
// Process all at once
}

3. Limit Query Results


var gr = new GlideRecord('incident');
[Link]('active', true);
[Link](100); // Limit results
[Link]();

4. Use GlideAggregate for Counts


// ❌ BAD
var gr = new GlideRecord('incident');
[Link]('assigned_to', userId);
[Link]();
var count = 0;
while ([Link]()) {
count++;
}

// ✅ GOOD
var agg = new GlideAggregate('incident');
[Link]('assigned_to', userId);
[Link]('COUNT');
[Link]();
if ([Link]()) {
var count = [Link]('COUNT');
}

5. Async for Heavy Operations

Use async business rules for:

 External API calls


 Complex calculations
 Processing large datasets
 Operations that don't need immediate results

Testing & Debugging


1. Logging
(function executeRule(current, previous) {

[Link]('BR: Processing incident ' + [Link]);


[Link]('Priority: ' + [Link]);
[Link]('Category: ' + [Link]);

// Log object details


[Link]('Current: ' + [Link]({
number: [Link](),
priority: [Link](),
state: [Link]()
}));

})(current, previous);

2. Using Scripts - Background

Navigate to System Definition > Scripts - Background

// Test your business rule logic


var inc = new GlideRecord('incident');
[Link]('INC0010001');

// Simulate the logic


if ([Link] == 6) {
[Link]('Incident is resolved');
}

[Link]('Priority: ' + [Link]);


[Link]('Category: ' + [Link]);

3. Check Execution

System Logs > System Log > All

 Filter by Source = Business Rule


 Check execution time and errors

4. Debug Mode

Enable debug logging:

[Link]('debug', '[Link]');

5. Common Debugging Techniques


(function executeRule(current, previous) {

// Check if running in correct context


[Link]('Is Insert: ' + [Link]());
[Link]('Is Update: ' + ![Link]());

// Check field changes


if (previous) {
[Link]('State changed: ' + [Link]());
[Link]('Old state: ' + [Link]);
[Link]('New state: ' + [Link]);
}

// Verify conditions
[Link]('Assignment group empty: ' + current.assignment_group.nil());

})(current, previous);
Advanced Topics
1. GlideDateTime Manipulation
// Create date objects
var gdt = new GlideDateTime();
var specificDate = new GlideDateTime('2024-01-15 10:30:00');

// Add/subtract time
[Link](7);
[Link](2);
[Link](30);
[Link](86400000); // milliseconds

// Compare dates
if ([Link](specificDate)) {
// gdt is later
}

if ([Link](specificDate)) {
// gdt is earlier
}

// Format
var displayValue = [Link]();
var internalValue = [Link]();

// Business hours calculation


var schedule = new GlideSchedule('8x5'); // Business hours schedule
var duration = [Link](startDate, endDate);

2. Working with Reference Fields


// Get referenced record details
var assignedUser = current.assigned_to.getRefRecord();
if (assignedUser) {
var userEmail = [Link]();
var userManager = [Link]();
}

// Set reference by sys_id


current.assignment_group.setValue(groupSysId);

// Set reference by display value


current.assignment_group.setDisplayValue('Service Desk');

// Check if reference is empty


if (current.assigned_to.nil()) {
// Reference is empty
}

3. GlideRecord Advanced Queries


// OR conditions
var gr = new GlideRecord('incident');
var qc = [Link]('priority', 1);
[Link]('priority', 2);
[Link]();
// IN operator
[Link]('state', 'IN', '1,2,3');

// NOT IN
[Link]('state', 'NOT IN', '6,7,8');

// NULL checks
[Link]('assigned_to');
[Link]('assignment_group');

// Date queries
[Link]('sys_created_on', '>=', [Link](7));
[Link]('due_date', '<', [Link]());

// Encoded queries (for complex conditions)


[Link]('priority=1^ORpriority=2^state!=7');

4. Script Include Integration


// Create Script Include: AssignmentHelper
var AssignmentHelper = [Link]();
[Link] = {

initialize: function() {
[Link] = 'Service Desk';
},

getOptimalAssignee: function(incident) {
// Complex logic to find best assignee
var group = incident.assignment_group.toString();

var members = new GlideRecord('sys_user_grmember');


[Link]('group', group);
[Link]();

var lowestWorkload = 999;


var optimalUser = null;

while ([Link]()) {
var workload =
this._calculateWorkload([Link]());
if (workload < lowestWorkload) {
lowestWorkload = workload;
optimalUser = [Link]();
}
}

return optimalUser;
},

_calculateWorkload: function(userId) {
var agg = new GlideAggregate('incident');
[Link]('assigned_to', userId);
[Link]('state', '<', 6);
[Link]('COUNT');
[Link]();

if ([Link]()) {
return parseInt([Link]('COUNT'));
}
return 0;
},

type: 'AssignmentHelper'
};
// Use in Business Rule
(function executeRule(current, previous) {

if (current.assigned_to.nil() && !current.assignment_group.nil()) {


var helper = new AssignmentHelper();
var assignee = [Link](current);

if (assignee) {
current.assigned_to = assignee;
}
}

})(current, previous);

5. Event Management
// Queue an event
[Link](
'[Link]', // Event name
current, // Record
current.assigned_to, // parm1
current.assignment_group // parm2
);

// Process event in Business Rule or Script Action


// When: Event fires = [Link]
(function executeRule(current, previous) {

var assignedTo = event.parm1; // User who was assigned


var group = event.parm2; // Assignment group

// Send notification
var email = new GlideEmailOutbound();
[Link]('New incident assigned: ' + [Link]);
[Link]('You have been assigned incident ' + [Link]);
[Link](assignedTo);
[Link]();

})(current, previous);

6. Complex Conditional Logic


(function executeRule(current, previous) {

// Multi-factor decision making


var shouldEscalate = false;
var escalationReasons = [];

// Check age
var ageHours = [Link](current.sys_created_on, [Link](),
true) / 3600;
if (ageHours > 24 && [Link] < 6) {
shouldEscalate = true;
[Link]('Open for ' + [Link](ageHours) + '
hours');
}

// Check reassignment count


if (current.reassignment_count > 2) {
shouldEscalate = true;
[Link]('Reassigned ' + current.reassignment_count +
' times');
}

// Check VIP status


if (current.caller_id.vip == true) {
shouldEscalate = true;
[Link]('VIP user');
}

// Check CI criticality
if (!current.cmdb_ci.nil()) {
var ci = current.cmdb_ci.getRefRecord();
if (ci.u_criticality == 'critical') {
shouldEscalate = true;
[Link]('Critical CI affected');
}
}

if (shouldEscalate) {
[Link] = 1;
[Link] = [Link](1, parseInt([Link]) - 1);
current.work_notes = 'AUTO-ESCALATED: ' + [Link](',
');

// Notify management
[Link]('[Link]', current);
}

})(current, previous);

Learning Path
Beginner Level

1. ✅ Understand current and previous objects


2. ✅ Learn When to execute (before/after/async)
3. ✅ Practice basic field manipulation
4. ✅ Write simple validation rules
5. ✅ Use conditions to limit execution

Intermediate Level

1. ✅ Master GlideRecord queries


2. ✅ Implement complex conditional logic
3. ✅ Work with reference fields
4. ✅ Use GlideDateTime for date calculations
5. ✅ Create Script Includes for reusable code
6. ✅ Implement error handling

Advanced Level

1. ✅ Optimize for performance


2. ✅ Implement pattern matching algorithms
3. ✅ Build intelligent automation
4. ✅ Integrate with external systems (REST/SOAP)
5. ✅ Design scalable, maintainable solutions
6. ✅ Handle complex business scenarios

Quick Reference Card


Essential Methods
// Current record
[Link]('field_name')
[Link]('field_name', value)
[Link]()
[Link]()
[Link](true)

// GlideRecord
[Link]('field', 'value')
[Link]()
[Link]()
[Link]()
[Link]()
[Link]()
[Link]()

// GlideSystem
[Link]()
[Link]('text')
[Link]('text')
[Link]()
[Link](n)
[Link](date1, date2, true)
[Link]('event_name', record)

// GlideDateTime
var gdt = new GlideDateTime()
[Link](n)
[Link](n)
[Link](otherDate)
[Link](otherDate)

Common Patterns
// Check if insert
if ([Link]()) { }

// Check if update
if (![Link]()) { }

// Check field changed


if (current.field_name.changes()) { }

// Check empty
if (current.field_name.nil()) { }

// Safe previous check


if (previous && [Link] != [Link]) { }

Practice Exercises
Exercise 1: Auto-Assignment

Create a business rule that assigns incidents based on category:

 Hardware → Hardware Support


 Software → Application Team
 Network → Network Operations

Exercise 2: Validation

Create a rule that prevents closing an incident without:

 Close notes
 Resolution code
 Actual end time

Exercise 3: Escalation

Create a rule that escalates incidents when:

 Open for more than 48 hours


 Priority is 1 or 2
 Not yet resolved

Exercise 4: Cascade Update

Create a rule that when a change request is approved, automatically approves all child tasks.

Exercise 5: Duplicate Detection

Create a rule that prevents creating duplicate incidents from the same user with the same
short description within 24 hours.

Resources
Official Documentation

 ServiceNow Product Documentation


 Developer Portal
 Community Forums
 Now Learning Platform

Practice Environments

 Personal Developer Instance ([Link])


 ServiceNow Simulator
 Practice Labs

Tips for Success

1. Start simple and build complexity gradually


2. Always test in a development instance
3. Use logging extensively for debugging
4. Read existing business rules to learn patterns
5. Join ServiceNow community forums
6. Take ServiceNow certification courses

Remember: Good business rules are:

 ✅ Simple and focused


 ✅ Well-documented
 ✅ Performance-optimized
 ✅ Easy to maintain
 ✅ Properly tested

1. Auto-Populate Assignment Group


When: Before insert Purpose: Automatically set assignment group based on category

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

if ([Link] == 'hardware') {

current.assignment_group.setValue('Hardware Support Team');


} else if ([Link] == 'software') {

current.assignment_group.setValue('Software Support Team');

} else if ([Link] == 'network') {

current.assignment_group.setValue('Network Operations');

})(current, previous);

2. Prevent Closure Without Resolution


When: Before update Purpose: Validate required fields before closing

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

if ([Link] == 7 && current.close_notes == '') { // 7 = Closed

[Link]('Close notes are required to close this incident');

[Link]('Cannot close without resolution notes');

[Link](true);

})(current, previous);

3. Calculate SLA Due Date


When: Before insert Purpose: Set due date based on priority

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

var gdt = new GlideDateTime();

if ([Link] == 1) {

[Link](4); // Critical - 4 hours

} else if ([Link] == 2) {

[Link](8); // High - 8 hours

} else if ([Link] == 3) {
[Link](3); // Medium - 3 days

} else {

[Link](7); // Low - 7 days

current.due_date = gdt;

})(current, previous);

4. Send Email Notification on Status Change


When: After update Purpose: Notify requester when ticket is resolved

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

if ([Link] == 6 && [Link] != 6) { // 6 = Resolved

var email = new GlideEmailOutbound();

[Link]('Your incident ' + [Link] + ' has been


resolved');

[Link]('Your incident has been resolved. Resolution: ' +


current.close_notes);

[Link](current.caller_id.email);

[Link]();

})(current, previous);

5. Auto-Escalate Overdue Tickets


When: After insert/update (scheduled daily) Purpose: Escalate tickets past due date

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

var now = new GlideDateTime();

var due = new GlideDateTime(current.due_date);


if ([Link] != 6 && [Link] != 7 && [Link](due)) {

[Link] = 1; // Escalated

[Link] = [Link](1, [Link] - 1); // Increase priority

[Link] = 'Auto-escalated due to SLA breach';

[Link]();

})(current, previous);

6. Prevent Duplicate Records


When: Before insert Purpose: Check for existing tickets from same user

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

var gr = new GlideRecord('incident');

[Link]('caller_id', current.caller_id);

[Link]('short_description', current.short_description);

[Link]('state', '!=', 7); // Not closed

[Link]('sys_created_on', '>', [Link](1)); // Within 24 hours

[Link]();

if ([Link]()) {

[Link]('A similar incident already exists: ' +


[Link]);

[Link](true);

})(current, previous);

7. Update Related Records


When: After update Purpose: Close related tasks when parent closes

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


if ([Link] == 7 && [Link] != 7) { // Closed

var tasks = new GlideRecord('sc_task');

[Link]('request_item', current.sys_id);

[Link]('state', '!=', 3); // Not closed

[Link]();

while ([Link]()) {

[Link] = 3; // Closed

tasks.close_notes = 'Auto-closed with parent request item';

[Link]();

})(current, previous);

Best Practices:
 Use Before rules for validation and setting values
 Use After rules for notifications and related record updates
 Keep business rules simple and focused on one task
 Use conditions to limit when the rule runs
 Avoid complex queries in synchronous rules
 Consider using Script Includes for reusable logic

1. Asynchronous Business Rule — Auto-create Change


Task
Use Case: When a Change Request moves to Implementation, automatically create a Change
Task after the record is committed (async for performance).

(function executeRule(current, previous) {

// Run only when state changes to "Implementation"

if ([Link]('implementation')) {
// Create Change Task asynchronously

var task = new GlideRecord('change_task');

[Link]();

task.change_request = current.sys_id;

task.short_description = 'Perform Implementation activities';

task.assigned_to = current.assigned_to;

[Link]();

[Link]('Change Task created for Change Request: ' +


[Link]);

})(current, previous);

Trigger: after update (set Advanced → Execute asynchronously)


Purpose: Offloads secondary operations to background for faster UI
response.

2. Conditional Data Update Using GlideAggregate


Use Case: Update Problem record with total number of open incidents linked to it whenever
an Incident’s state changes.

(function executeRule(current, previous) {

if (current.problem_id && [Link]()) {

var agg = new GlideAggregate('incident');

[Link]('COUNT');

[Link]('problem_id', current.problem_id);

[Link]('state', '!=', 7); // not Closed

[Link]();

if ([Link]()) {
var prob = new GlideRecord('problem');

if ([Link](current.problem_id)) {

prob.u_open_incident_count = [Link]('COUNT');

[Link]();

})(current, previous);

Trigger: after update


Table: incident
Purpose: Maintains real-time metrics using GlideAggregate for
performance.

3. Auto-sync Between Two Tables (Custom Integration)


Use Case: When an Asset is updated, automatically sync key fields to Custom Hardware
Inventory table.

(function executeRule(current, previous) {

var inv = new GlideRecord('u_hardware_inventory');

[Link]('u_asset', current.sys_id);

[Link]();

if ([Link]()) {

inv.u_serial_number = current.serial_number;

inv.u_model = [Link];

inv.u_location = [Link];

[Link]();

} else {

[Link]();

inv.u_asset = current.sys_id;

inv.u_serial_number = current.serial_number;
inv.u_model = [Link];

inv.u_location = [Link];

[Link]();

})(current, previous);

Trigger: after update


Table: alm_asset
Purpose: Keeps custom integration tables synchronized.

. Restrict Update Based on Workflow Stage


Use Case: In a Change Request, prevent users from updating Risk and Impact Analysis once
it’s approved by CAB.

(function executeRule(current, previous) {

// Check if CAB approved

if (current.u_cab_approved == true &&


current.u_risk_impact.changes()) {

[Link]("Risk and Impact analysis cannot be modified


after CAB approval.");

[Link](true);

})(current, previous);

Best Practices Summary


Area Recommendation
Performance Use async rules for post-processing tasks.
Query Optimization Always filter GlideRecord queries precisely (use indexed fields).
Use [Link]() and [Link](true)
Error Handling
for user-safe errors.
Avoid Loops on
Always check for field changes using .changes() or .changesTo().
Updates
Debugging Use [Link]() during testing (not in production).

Optional Enhancement — Restrict Edits Post-Approval


Table: change_request
When: before update

(function executeRule(current, previous) {

if (previous.u_approval_status == 'Approved' &&


current.short_description.changes()) {

[Link]("Approved Change Requests cannot be


modified.");

[Link](true);

})(current, previous);

Common questions

Powered by AI

The execution order of business rules is crucial because it determines the sequence in which data manipulations and operations occur. By setting appropriate order values (e.g., 100, 200, 300), developers can ensure that certain actions, such as validating data, calculating fields, or setting assignments, happen in a logical and effective order. Mismanagement of execution order can lead to errors, such as data being calculated based on incomplete or old information, impacting the reliability and correctness of system processes .

GlideAggregate is preferred over GlideRecord for operations that involve counting records or other aggregate computations, as it is optimized for such tasks. Using GlideAggregate can significantly improve performance by reducing the amount of data retrieved and processed. It allows for aggregating query results at the database level, which is more efficient than retrieving record data individually and then performing operations on them in memory. This leads to better performance when calculating counts, sums, averages, etc., especially with large datasets .

Logging and debugging are fundamental for developing and troubleshooting business rules as they provide insights into the behavior and execution flow of the rules. By leveraging methods like gs.info() and gs.debug(), developers can trace the execution path and inspect field values and state changes, which aids in identifying logic errors or unexpected behaviors. Debugging allows developers to verify field changes and rule triggers in different contexts, ensuring that the rules perform as intended across various scenarios .

Recursive updates in business rules can lead to infinite loops, especially if changes in record fields continuously trigger the same rule. To mitigate this risk, it's important to use before rules for making field changes and avoid calling the update() method within the execution of a rule itself. Additionally, checking a flag or condition to determine if a record has already been processed can prevent recursion by ensuring the rule only acts on a record once. This is crucial for maintaining system stability and performance .

Before rules are executed first in the business rule lifecycle and are used primarily for data validation, setting calculated fields, and determining if a record should be saved. After rules run after the database operation and are typically used to trigger workflows, send notifications, and update related records. Async rules run in the background and are suitable for heavy computations and external API calls, ensuring that these operations do not impact the performance of more immediate tasks .

An auto-assignment logic can be optimized by using condition checks within a 'before insert' business rule to automatically determine and set the assignment group based on the incident category. Utilizing a mapping structure, such as an object or Script Include, reduces redundancy and makes the rule easily adaptable for different categories. Furthermore, ensuring that conditions prevent unnecessary executions enhances the efficiency and responsiveness of incident handling processes .

Conditional data updates using GlideAggregate allow for real-time metrics accuracy by maintaining updated counts of related records whenever a state changes. For instance, by counting open incidents tied to a problem record, the business rule ensures that the problem record reflects the current number of associated incidents. This method efficiently updates related records with precise data using database-side aggregations, avoiding the need for synchronous querying loops, and thus maintaining accurate and up-to-date information without impacting system performance .

Script Includes promote code reusability and modularity within business rules. By encapsulating logic that can be reused across multiple rules, Script Includes reduce duplication and simplify maintenance. This design allows developers to update logic in one place rather than across potentially numerous business rules. Using Script Includes is particularly beneficial in systems with complex rule sets or frequent changes, as it enhances maintainability and scalability of the codebase .

When testing business rules in a development environment, it's important to start with simple logic and gradually add complexity, ensuring each stage works as intended. Extensive testing should include the use of logging for monitoring rule execution and troubleshooting potential errors. Developers should perform stress tests for scalability, especially for rules intended to handle large datasets. Testing should also account for all access levels and user inputs to prevent unexpected behaviors in production. This comprehensive testing ensures robust performance and minimal disruptions when rules are deployed to production .

Error handling in business rules is crucial to prevent disruptions in system operations and ensure a smooth user experience. Safe error handling can be implemented using methods such as gs.addErrorMessage() to communicate issues clearly to users and current.setAbortAction(true) to halt operations when critical errors occur. These methods ensure that errors are logged and communicated effectively, preventing erroneous data processing and maintaining the integrity and reliability of the system's operations .

You might also like