sla-management
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSLA Management for ServiceNow
ServiceNow的SLA管理
SLA (Service Level Agreement) Management tracks and ensures service commitments are met.
SLA(服务水平协议)管理用于跟踪并确保服务承诺得以兑现。
SLA Components
SLA组件
| Component | Table | Purpose |
|---|---|---|
| SLA Definition | contract_sla | SLA rules and conditions |
| Task SLA | task_sla | SLA instance on a task |
| SLA Workflow | wf_workflow | SLA breach notifications |
| SLA Schedule | cmn_schedule | Business hours definition |
| 组件 | 表 | 用途 |
|---|---|---|
| SLA Definition | contract_sla | SLA规则与条件 |
| Task SLA | task_sla | 任务关联的SLA实例 |
| SLA Workflow | wf_workflow | SLA违约通知 |
| SLA Schedule | cmn_schedule | 营业时间定义 |
SLA Flow
SLA流程
Task Created
↓
SLA Definition Conditions Match
↓
Task SLA Record Created
↓
Timer Starts (based on schedule)
↓
SLA Stages: In Progress → Breached (if not met)
↓
Task Resolved/Closed
↓
SLA Achieved or BreachedTask Created
↓
SLA Definition Conditions Match
↓
Task SLA Record Created
↓
Timer Starts (based on schedule)
↓
SLA Stages: In Progress → Breached (if not met)
↓
Task Resolved/Closed
↓
SLA Achieved or BreachedSLA Definition (ES5)
SLA定义(ES5)
Create SLA Definition
创建SLA定义
javascript
// Create SLA Definition (ES5 ONLY!)
var sla = new GlideRecord('contract_sla');
sla.initialize();
// Basic info
sla.setValue('name', 'P1 Incident Response Time');
sla.setValue('type', 'SLA'); // SLA, OLA, UC
sla.setValue('table', 'incident');
// Target duration
sla.setValue('duration_type', 'response'); // response or resolution
sla.setValue('duration', 'PT15M'); // 15 minutes (ISO 8601)
// Conditions - when SLA attaches
sla.setValue('start_condition', 'priority=1^active=true');
sla.setValue('stop_condition', 'work_notes.changesTo()');
sla.setValue('pause_condition', 'state=3'); // Pause when On Hold
sla.setValue('cancel_condition', 'state=8'); // Cancel when Cancelled
// Schedule (business hours)
sla.setValue('schedule', getScheduleSysId('8-5 M-F'));
// Enable
sla.setValue('active', true);
sla.insert();javascript
// Create SLA Definition (ES5 ONLY!)
var sla = new GlideRecord('contract_sla');
sla.initialize();
// Basic info
sla.setValue('name', 'P1 Incident Response Time');
sla.setValue('type', 'SLA'); // SLA, OLA, UC
sla.setValue('table', 'incident');
// Target duration
sla.setValue('duration_type', 'response'); // response or resolution
sla.setValue('duration', 'PT15M'); // 15 minutes (ISO 8601)
// Conditions - when SLA attaches
sla.setValue('start_condition', 'priority=1^active=true');
sla.setValue('stop_condition', 'work_notes.changesTo()');
sla.setValue('pause_condition', 'state=3'); // Pause when On Hold
sla.setValue('cancel_condition', 'state=8'); // Cancel when Cancelled
// Schedule (business hours)
sla.setValue('schedule', getScheduleSysId('8-5 M-F'));
// Enable
sla.setValue('active', true);
sla.insert();SLA Conditions Explained
SLA条件说明
javascript
// Start Condition: When SLA timer begins
// Example: P1 incidents when created
var startCondition = 'priority=1^active=true^sys_created_onRELATIVEGT@minute@ago@0';
// Stop Condition: When SLA is achieved
// Example: When work notes are added (response) or resolved (resolution)
var responseStop = 'work_notes.changes()';
var resolutionStop = 'state=6^ORstate=7'; // Resolved or Closed
// Pause Condition: Timer pauses
// Example: On Hold or Awaiting User Info
var pauseCondition = 'state=3^ORstate=-5';
// Cancel Condition: SLA cancelled without breach
// Example: Incident cancelled or duplicate
var cancelCondition = 'state=8^ORclose_code=Duplicate';javascript
// Start Condition: When SLA timer begins
// Example: P1 incidents when created
var startCondition = 'priority=1^active=true^sys_created_onRELATIVEGT@minute@ago@0';
// Stop Condition: When SLA is achieved
// Example: When work notes are added (response) or resolved (resolution)
var responseStop = 'work_notes.changes()';
var resolutionStop = 'state=6^ORstate=7'; // Resolved or Closed
// Pause Condition: Timer pauses
// Example: On Hold or Awaiting User Info
var pauseCondition = 'state=3^ORstate=-5';
// Cancel Condition: SLA cancelled without breach
// Example: Incident cancelled or duplicate
var cancelCondition = 'state=8^ORclose_code=Duplicate';Task SLA Operations (ES5)
任务SLA操作(ES5)
Query Task SLAs
查询任务SLA
javascript
// Find SLAs for an incident (ES5 ONLY!)
var incidentSysId = 'incident_sys_id';
var taskSla = new GlideRecord('task_sla');
taskSla.addQuery('task', incidentSysId);
taskSla.query();
while (taskSla.next()) {
gs.info('SLA: ' + taskSla.sla.getDisplayValue() +
' | Stage: ' + taskSla.stage.getDisplayValue() +
' | Breached: ' + taskSla.getValue('has_breached') +
' | Planned End: ' + taskSla.getValue('planned_end_time'));
}javascript
// Find SLAs for an incident (ES5 ONLY!)
var incidentSysId = 'incident_sys_id';
var taskSla = new GlideRecord('task_sla');
taskSla.addQuery('task', incidentSysId);
taskSla.query();
while (taskSla.next()) {
gs.info('SLA: ' + taskSla.sla.getDisplayValue() +
' | Stage: ' + taskSla.stage.getDisplayValue() +
' | Breached: ' + taskSla.getValue('has_breached') +
' | Planned End: ' + taskSla.getValue('planned_end_time'));
}Check SLA Status
检查SLA状态
javascript
// SLA Status Helper (ES5 ONLY!)
var SLAHelper = Class.create();
SLAHelper.prototype = {
initialize: function() {},
/**
* Get SLA status for a task
* @param {string} taskSysId - Task sys_id
* @returns {Array} - Array of SLA status objects
*/
getSLAStatus: function(taskSysId) {
var slaStatuses = [];
var taskSla = new GlideRecord('task_sla');
taskSla.addQuery('task', taskSysId);
taskSla.addQuery('active', true);
taskSla.query();
while (taskSla.next()) {
var now = new GlideDateTime();
var plannedEnd = new GlideDateTime(taskSla.getValue('planned_end_time'));
var timeLeft = GlideDateTime.subtract(now, plannedEnd);
slaStatuses.push({
name: taskSla.sla.getDisplayValue(),
stage: taskSla.stage.getDisplayValue(),
hasBreached: taskSla.getValue('has_breached') === 'true',
percentageComplete: taskSla.getValue('percentage'),
plannedEnd: taskSla.getValue('planned_end_time'),
timeLeft: this._formatDuration(timeLeft),
isAtRisk: this._isAtRisk(taskSla)
});
}
return slaStatuses;
},
/**
* Check if any SLA is at risk (>75% elapsed)
*/
_isAtRisk: function(taskSla) {
var percentage = parseFloat(taskSla.getValue('percentage'));
return percentage >= 75 && taskSla.getValue('has_breached') !== 'true';
},
_formatDuration: function(duration) {
var totalSeconds = duration.getNumericValue() / 1000;
var hours = Math.floor(totalSeconds / 3600);
var minutes = Math.floor((totalSeconds % 3600) / 60);
return hours + 'h ' + minutes + 'm';
},
type: 'SLAHelper'
};javascript
// SLA Status Helper (ES5 ONLY!)
var SLAHelper = Class.create();
SLAHelper.prototype = {
initialize: function() {},
/**
* Get SLA status for a task
* @param {string} taskSysId - Task sys_id
* @returns {Array} - Array of SLA status objects
*/
getSLAStatus: function(taskSysId) {
var slaStatuses = [];
var taskSla = new GlideRecord('task_sla');
taskSla.addQuery('task', taskSysId);
taskSla.addQuery('active', true);
taskSla.query();
while (taskSla.next()) {
var now = new GlideDateTime();
var plannedEnd = new GlideDateTime(taskSla.getValue('planned_end_time'));
var timeLeft = GlideDateTime.subtract(now, plannedEnd);
slaStatuses.push({
name: taskSla.sla.getDisplayValue(),
stage: taskSla.stage.getDisplayValue(),
hasBreached: taskSla.getValue('has_breached') === 'true',
percentageComplete: taskSla.getValue('percentage'),
plannedEnd: taskSla.getValue('planned_end_time'),
timeLeft: this._formatDuration(timeLeft),
isAtRisk: this._isAtRisk(taskSla)
});
}
return slaStatuses;
},
/**
* Check if any SLA is at risk (>75% elapsed)
*/
_isAtRisk: function(taskSla) {
var percentage = parseFloat(taskSla.getValue('percentage'));
return percentage >= 75 && taskSla.getValue('has_breached') !== 'true';
},
_formatDuration: function(duration) {
var totalSeconds = duration.getNumericValue() / 1000;
var hours = Math.floor(totalSeconds / 3600);
var minutes = Math.floor((totalSeconds % 3600) / 60);
return hours + 'h ' + minutes + 'm';
},
type: 'SLAHelper'
};Pause/Resume SLA
暂停/恢复SLA
javascript
// Pause SLAs when incident goes On Hold (ES5 ONLY!)
// Business Rule: after, update, incident
(function executeRule(current, previous) {
// Check if state changed to On Hold
if (current.state.changesTo('3')) {
pauseIncidentSLAs(current.getUniqueValue());
}
// Check if state changed from On Hold
if (previous.state == '3' && current.state != '3') {
resumeIncidentSLAs(current.getUniqueValue());
}
})(current, previous);
function pauseIncidentSLAs(incidentId) {
var taskSla = new GlideRecord('task_sla');
taskSla.addQuery('task', incidentId);
taskSla.addQuery('active', true);
taskSla.addQuery('stage', '!=', 'breached');
taskSla.query();
while (taskSla.next()) {
var slaDef = new GlideRecord('contract_sla');
if (slaDef.get(taskSla.getValue('sla'))) {
// Only pause if SLA has pause condition
if (slaDef.getValue('pause_condition')) {
taskSla.pause = true;
taskSla.pause_time = new GlideDateTime();
taskSla.update();
}
}
}
}javascript
// Pause SLAs when incident goes On Hold (ES5 ONLY!)
// Business Rule: after, update, incident
(function executeRule(current, previous) {
// Check if state changed to On Hold
if (current.state.changesTo('3')) {
pauseIncidentSLAs(current.getUniqueValue());
}
// Check if state changed from On Hold
if (previous.state == '3' && current.state != '3') {
resumeIncidentSLAs(current.getUniqueValue());
}
})(current, previous);
function pauseIncidentSLAs(incidentId) {
var taskSla = new GlideRecord('task_sla');
taskSla.addQuery('task', incidentId);
taskSla.addQuery('active', true);
taskSla.addQuery('stage', '!=', 'breached');
taskSla.query();
while (taskSla.next()) {
var slaDef = new GlideRecord('contract_sla');
if (slaDef.get(taskSla.getValue('sla'))) {
// Only pause if SLA has pause condition
if (slaDef.getValue('pause_condition')) {
taskSla.pause = true;
taskSla.pause_time = new GlideDateTime();
taskSla.update();
}
}
}
}SLA Workflows
SLA工作流
Breach Notification Script (ES5)
违约通知脚本(ES5)
javascript
// SLA Workflow Activity: Send breach notification (ES5 ONLY!)
(function executeActivity() {
var taskSla = current;
var task = taskSla.task.getRefRecord();
// Get escalation recipients
var recipients = [];
// Add assigned user
if (task.assigned_to) {
recipients.push(task.assigned_to.getValue('email'));
}
// Add assignment group manager
if (task.assignment_group) {
var group = task.assignment_group.getRefRecord();
if (group.manager) {
recipients.push(group.manager.email);
}
}
// Send notification
if (recipients.length > 0) {
gs.eventQueue('sla.breach.notification', task, recipients.join(','), taskSla.sla.getDisplayValue());
}
})();javascript
// SLA Workflow Activity: Send breach notification (ES5 ONLY!)
(function executeActivity() {
var taskSla = current;
var task = taskSla.task.getRefRecord();
// Get escalation recipients
var recipients = [];
// Add assigned user
if (task.assigned_to) {
recipients.push(task.assigned_to.getValue('email'));
}
// Add assignment group manager
if (task.assignment_group) {
var group = task.assignment_group.getRefRecord();
if (group.manager) {
recipients.push(group.manager.email);
}
}
// Send notification
if (recipients.length > 0) {
gs.eventQueue('sla.breach.notification', task, recipients.join(','), taskSla.sla.getDisplayValue());
}
})();SLA Escalation Rules
SLA升级规则
javascript
// SLA Escalation Script Include (ES5 ONLY!)
var SLAEscalation = Class.create();
SLAEscalation.prototype = {
initialize: function() {},
/**
* Escalate breached SLA
*/
escalateBreached: function(taskSlaSysId) {
var taskSla = new GlideRecord('task_sla');
if (!taskSla.get(taskSlaSysId)) {
return false;
}
var task = taskSla.task.getRefRecord();
// Increase priority
var currentPriority = parseInt(task.getValue('priority'), 10);
if (currentPriority > 1) {
task.setValue('priority', currentPriority - 1);
}
// Set escalation flag
task.setValue('escalation', 1);
// Add work note
task.work_notes = 'SLA Breached: ' + taskSla.sla.getDisplayValue() +
'\nAutomatic escalation applied.';
task.update();
// Notify on-call
this._notifyOnCall(task);
return true;
},
_notifyOnCall: function(task) {
// Get on-call schedule
var oncall = new OnCallRotation();
var onCallUser = oncall.getOnCallUser(task.assignment_group);
if (onCallUser) {
gs.eventQueue('sla.oncall.notification', task, onCallUser.sys_id, '');
}
},
type: 'SLAEscalation'
};javascript
// SLA Escalation Script Include (ES5 ONLY!)
var SLAEscalation = Class.create();
SLAEscalation.prototype = {
initialize: function() {},
/**
* Escalate breached SLA
*/
escalateBreached: function(taskSlaSysId) {
var taskSla = new GlideRecord('task_sla');
if (!taskSla.get(taskSlaSysId)) {
return false;
}
var task = taskSla.task.getRefRecord();
// Increase priority
var currentPriority = parseInt(task.getValue('priority'), 10);
if (currentPriority > 1) {
task.setValue('priority', currentPriority - 1);
}
// Set escalation flag
task.setValue('escalation', 1);
// Add work note
task.work_notes = 'SLA Breached: ' + taskSla.sla.getDisplayValue() +
'\nAutomatic escalation applied.';
task.update();
// Notify on-call
this._notifyOnCall(task);
return true;
},
_notifyOnCall: function(task) {
// Get on-call schedule
var oncall = new OnCallRotation();
var onCallUser = oncall.getOnCallUser(task.assignment_group);
if (onCallUser) {
gs.eventQueue('sla.oncall.notification', task, onCallUser.sys_id, '');
}
},
type: 'SLAEscalation'
};SLA Reports
SLA报表
SLA Compliance Query (ES5)
SLA合规性查询(ES5)
javascript
// Calculate SLA compliance rate (ES5 ONLY!)
function getSLAComplianceRate(slaName, startDate, endDate) {
var ga = new GlideAggregate('task_sla');
ga.addQuery('sla.name', slaName);
ga.addQuery('end_time', '>=', startDate);
ga.addQuery('end_time', '<=', endDate);
ga.addQuery('active', false); // Completed SLAs only
ga.addAggregate('COUNT');
ga.addAggregate('COUNT', 'has_breached');
ga.groupBy('has_breached');
ga.query();
var total = 0;
var breached = 0;
while (ga.next()) {
var count = parseInt(ga.getAggregate('COUNT'), 10);
total += count;
if (ga.getValue('has_breached') === 'true') {
breached = count;
}
}
if (total === 0) {
return { compliance: 100, total: 0, breached: 0 };
}
var achieved = total - breached;
var compliance = Math.round((achieved / total) * 100 * 10) / 10;
return {
compliance: compliance,
total: total,
achieved: achieved,
breached: breached
};
}
// Usage
var stats = getSLAComplianceRate('P1 Incident Response',
gs.beginningOfThisMonth(),
gs.endOfThisMonth());
gs.info('P1 Response SLA Compliance: ' + stats.compliance + '%');javascript
// Calculate SLA compliance rate (ES5 ONLY!)
function getSLAComplianceRate(slaName, startDate, endDate) {
var ga = new GlideAggregate('task_sla');
ga.addQuery('sla.name', slaName);
ga.addQuery('end_time', '>=', startDate);
ga.addQuery('end_time', '<=', endDate);
ga.addQuery('active', false); // Completed SLAs only
ga.addAggregate('COUNT');
ga.addAggregate('COUNT', 'has_breached');
ga.groupBy('has_breached');
ga.query();
var total = 0;
var breached = 0;
while (ga.next()) {
var count = parseInt(ga.getAggregate('COUNT'), 10);
total += count;
if (ga.getValue('has_breached') === 'true') {
breached = count;
}
}
if (total === 0) {
return { compliance: 100, total: 0, breached: 0 };
}
var achieved = total - breached;
var compliance = Math.round((achieved / total) * 100 * 10) / 10;
return {
compliance: compliance,
total: total,
achieved: achieved,
breached: breached
};
}
// Usage
var stats = getSLAComplianceRate('P1 Incident Response',
gs.beginningOfThisMonth(),
gs.endOfThisMonth());
gs.info('P1 Response SLA Compliance: ' + stats.compliance + '%');MCP Tool Integration
MCP工具集成
Available Tools
可用工具
| Tool | Purpose |
|---|---|
| Find SLA definitions |
| Query task_sla records |
| Test SLA scripts |
| Create SLA triggers |
| 工具 | 用途 |
|---|---|
| 查找SLA定义 |
| 查询task_sla记录 |
| 测试SLA脚本 |
| 创建SLA触发器 |
Example Workflow
示例工作流
javascript
// 1. Find existing SLAs
await snow_find_artifact({
type: 'contract_sla',
name: 'P1'
});
// 2. Query SLA breaches
await snow_query_table({
table: 'task_sla',
query: 'has_breached=true^end_time>=javascript:gs.beginningOfThisMonth()',
fields: 'sla,task,end_time,business_duration'
});
// 3. Check SLA compliance
await snow_execute_script_with_output({
script: 'var stats = getSLAComplianceRate("P1 Response", gs.beginningOfThisMonth(), gs.endOfThisMonth()); gs.info(JSON.stringify(stats));'
});javascript
// 1. Find existing SLAs
await snow_find_artifact({
type: 'contract_sla',
name: 'P1'
});
// 2. Query SLA breaches
await snow_query_table({
table: 'task_sla',
query: 'has_breached=true^end_time>=javascript:gs.beginningOfThisMonth()',
fields: 'sla,task,end_time,business_duration'
});
// 3. Check SLA compliance
await snow_execute_script_with_output({
script: 'var stats = getSLAComplianceRate("P1 Response", gs.beginningOfThisMonth(), gs.endOfThisMonth()); gs.info(JSON.stringify(stats));'
});Best Practices
最佳实践
- Clear Names - "P1 Incident Response 15min"
- Business Hours - Use appropriate schedules
- Pause Conditions - Pause for external waits
- Escalation - Notify before breach
- Metrics - Track compliance rates
- Testing - Test with various scenarios
- Documentation - Document SLA terms
- ES5 Only - No modern JavaScript syntax
- 名称清晰 - 例如“P1事件响应15分钟”
- 营业时间 - 使用合适的时间计划
- 暂停条件 - 外部等待时暂停计时
- 升级机制 - 违约前发送通知
- 指标跟踪 - 跟踪合规率
- 测试验证 - 用多种场景测试
- 文档记录 - 记录SLA条款
- 仅使用ES5 - 不使用现代JavaScript语法