sla-management

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SLA Management for ServiceNow

ServiceNow的SLA管理

SLA (Service Level Agreement) Management tracks and ensures service commitments are met.
SLA(服务水平协议)管理用于跟踪并确保服务承诺得以兑现。

SLA Components

SLA组件

ComponentTablePurpose
SLA Definitioncontract_slaSLA rules and conditions
Task SLAtask_slaSLA instance on a task
SLA Workflowwf_workflowSLA breach notifications
SLA Schedulecmn_scheduleBusiness hours definition
组件用途
SLA Definitioncontract_slaSLA规则与条件
Task SLAtask_sla任务关联的SLA实例
SLA Workflowwf_workflowSLA违约通知
SLA Schedulecmn_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 Breached
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 Breached

SLA 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

可用工具

ToolPurpose
snow_find_artifact
Find SLA definitions
snow_query_table
Query task_sla records
snow_execute_script_with_output
Test SLA scripts
snow_create_business_rule
Create SLA triggers
工具用途
snow_find_artifact
查找SLA定义
snow_query_table
查询task_sla记录
snow_execute_script_with_output
测试SLA脚本
snow_create_business_rule
创建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

最佳实践

  1. Clear Names - "P1 Incident Response 15min"
  2. Business Hours - Use appropriate schedules
  3. Pause Conditions - Pause for external waits
  4. Escalation - Notify before breach
  5. Metrics - Track compliance rates
  6. Testing - Test with various scenarios
  7. Documentation - Document SLA terms
  8. ES5 Only - No modern JavaScript syntax
  1. 名称清晰 - 例如“P1事件响应15分钟”
  2. 营业时间 - 使用合适的时间计划
  3. 暂停条件 - 外部等待时暂停计时
  4. 升级机制 - 违约前发送通知
  5. 指标跟踪 - 跟踪合规率
  6. 测试验证 - 用多种场景测试
  7. 文档记录 - 记录SLA条款
  8. 仅使用ES5 - 不使用现代JavaScript语法