Skip to Content

Async Notification with Complex Conditions

Send notifications asynchronously based on complex business logic, preventing delays in record save operations.

Table: incident When: async
#async #notification #email #alerting #escalation #insert #update #complex-logic

Script Code

JavaScript
1(function executeRule(current, previous /*null when async*/) {
2
3  // Async Business Rules run in background after the transaction completes
4  // Use for notifications, integrations, and non-critical updates
5  // Note: 'previous' is null in async business rules
6
7  try {
8    // Configuration
9    var notificationEnabled = gs.getProperty('custom.notifications.enabled', 'true') === 'true';
10
11    if (!notificationEnabled) {
12      gs.info('Notifications disabled via system property');
13      return;
14    }
15
16    // Determine notification scenarios
17    var shouldNotify = false;
18    var notificationType = '';
19    var recipients = [];
20    var additionalInfo = {};
21
22    // Scenario 1: High-priority incident created
23    if (current.isNewRecord() && current.priority.toString() === '1') {
24      shouldNotify = true;
25      notificationType = 'high_priority_created';
26
27      // Notify assignment group manager
28      if (current.assignment_group) {
29        var groupManager = getGroupManager(current.assignment_group.toString());
30        if (groupManager) {
31          recipients.push(groupManager);
32        }
33      }
34
35      // Notify incident manager role
36      recipients = recipients.concat(getUsersWithRole('incident_manager'));
37
38      additionalInfo.reason = 'High-priority incident requires immediate attention';
39    }
40
41    // Scenario 2: Incident reassigned multiple times (potential issue)
42    if (!current.isNewRecord()) {
43      var reassignmentCount = getReassignmentCount(current.sys_id.toString());
44
45      if (reassignmentCount >= 3) {
46        shouldNotify = true;
47        notificationType = 'excessive_reassignments';
48
49        // Notify service delivery manager
50        recipients = recipients.concat(getUsersWithRole('service_delivery_manager'));
51
52        additionalInfo.reason = 'Incident reassigned ' + reassignmentCount + ' times';
53        additionalInfo.reassignmentCount = reassignmentCount;
54      }
55    }
56
57    // Scenario 3: SLA breach imminent (within 30 minutes)
58    if (current.sla_due) {
59      var slaDue = new GlideDateTime(current.sla_due);
60      var now = new GlideDateTime();
61      var timeUntilDue = GlideDateTime.subtract(now, slaDue);
62      var minutesUntilDue = timeUntilDue.getNumericValue() / (1000 * 60);
63
64      if (minutesUntilDue > 0 && minutesUntilDue <= 30) {
65        shouldNotify = true;
66        notificationType = 'sla_breach_imminent';
67
68        // Notify assigned user and their manager
69        if (current.assigned_to) {
70          recipients.push(current.assigned_to.toString());
71
72          var assigneeManager = current.assigned_to.manager.toString();
73          if (assigneeManager) {
74            recipients.push(assigneeManager);
75          }
76        }
77
78        additionalInfo.reason = 'SLA breach in ' + minutesUntilDue.toFixed(0) + ' minutes';
79        additionalInfo.minutesUntilDue = minutesUntilDue.toFixed(0);
80      }
81    }
82
83    // Scenario 4: VIP caller incident
84    if (current.caller_id && current.caller_id.vip.toString() === 'true') {
85      shouldNotify = true;
86      notificationType = 'vip_incident';
87
88      // Notify VIP support team
89      recipients = recipients.concat(getUsersInGroup('VIP Support'));
90
91      // Notify caller's account manager if exists
92      if (current.caller_id.u_account_manager) {
93        recipients.push(current.caller_id.u_account_manager.toString());
94      }
95
96      additionalInfo.reason = 'VIP caller requires priority attention';
97    }
98
99    // Scenario 5: Incident age threshold exceeded
100    if (current.opened_at) {
101      var opened = new GlideDateTime(current.opened_at);
102      var now = new GlideDateTime();
103      var age = GlideDateTime.subtract(opened, now);
104      var ageHours = Math.abs(age.getNumericValue()) / (1000 * 60 * 60);
105
106      // Notify if incident open > 48 hours
107      if (ageHours > 48 && current.state.toString() !== '6') {  // Not resolved
108        shouldNotify = true;
109        notificationType = 'aging_incident';
110
111        // Notify assignment group and manager
112        if (current.assignment_group) {
113          recipients = recipients.concat(getGroupMembers(current.assignment_group.toString()));
114        }
115
116        additionalInfo.reason = 'Incident open for ' + ageHours.toFixed(0) + ' hours';
117        additionalInfo.ageHours = ageHours.toFixed(0);
118      }
119    }
120
121    // Send notifications if needed
122    if (shouldNotify && recipients.length > 0) {
123      // Remove duplicates
124      recipients = removeDuplicates(recipients);
125
126      // Send notification to each recipient
127      recipients.forEach(function(recipientId) {
128        sendNotification(recipientId, current, notificationType, additionalInfo);
129      });
130
131      gs.info('Sent ' + notificationType + ' notifications for incident ' + 
132              current.number + ' to ' + recipients.length + ' recipients');
133    }
134
135  } catch (e) {
136    gs.error('Async notification BR error for incident ' + current.number + ': ' + e.message);
137  }
138
139  // Helper functions
140  function getGroupManager(groupId) {
141    var grGroup = new GlideRecord('sys_user_group');
142    if (grGroup.get(groupId) && grGroup.manager) {
143      return grGroup.manager.toString();
144    }
145    return null;
146  }
147
148  function getUsersWithRole(roleName) {
149    var users = [];
150    var grUserRole = new GlideRecord('sys_user_has_role');
151    grUserRole.addQuery('role.name', roleName);
152    grUserRole.addQuery('user.active', 'true');
153    grUserRole.query();
154
155    while (grUserRole.next()) {
156      users.push(grUserRole.user.toString());
157    }
158    return users;
159  }
160
161  function getUsersInGroup(groupName) {
162    var users = [];
163    var grGroup = new GlideRecord('sys_user_group');
164    grGroup.addQuery('name', groupName);
165    grGroup.query();
166
167    if (grGroup.next()) {
168      var grMember = new GlideRecord('sys_user_grmember');
169      grMember.addQuery('group', grGroup.sys_id);
170      grMember.query();
171
172      while (grMember.next()) {
173        users.push(grMember.user.toString());
174      }
175    }
176    return users;
177  }
178
179  function getGroupMembers(groupId) {
180    var users = [];
181    var grMember = new GlideRecord('sys_user_grmember');
182    grMember.addQuery('group', groupId);
183    grMember.query();
184
185    while (grMember.next()) {
186      users.push(grMember.user.toString());
187    }
188    return users;
189  }
190
191  function getReassignmentCount(incidentId) {
192    var ga = new GlideAggregate('sys_audit');
193    ga.addQuery('tablename', 'incident');
194    ga.addQuery('documentkey', incidentId);
195    ga.addQuery('fieldname', 'assignment_group');
196    ga.addAggregate('COUNT');
197    ga.query();
198
199    if (ga.next()) {
200      return parseInt(ga.getAggregate('COUNT'));
201    }
202    return 0;
203  }
204
205  function removeDuplicates(arr) {
206    return arr.filter(function(item, index) {
207      return arr.indexOf(item) === index;
208    });
209  }
210
211  function sendNotification(userId, incident, type, info) {
212    // Create notification using gs.eventQueue or direct email
213    gs.eventQueue('custom.incident.notification', incident, userId, type, 
214                  JSON.stringify(info));
215
216    // Alternative: Send email directly
217    /*

218  }
219
220})(current, previous);
221      email.setSubject('Incident Alert: ' + incident.number);
222      email.setBody('Alert Type: ' + type + '\nReason: ' + info.reason);
223      email.addAddress(grUser.email.toString());
224      email.send();
225    }
226    */
227  }
228
229})(current, previous);

How to Use

1. Create an async Business Rule on incident table 2. Check "Insert" and "Update" checkboxes 3. Customize notification scenarios for your requirements 4. Create corresponding notification records or email templates 5. Test with various incident scenarios 6. Monitor system logs for notification delivery 7. Set up system property for enabling/disabling notifications 8. Consider notification throttling to prevent spam

Explore More Scripts

Browse our complete library of ServiceNow scripts

View All Scripts