sla-management

安装量: 50
排名: #14813

安装

npx skills add https://github.com/groeimetai/snow-flow --skill sla-management

SLA (Service Level Agreement) Management tracks and ensures service commitments are met.

SLA Components

| 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 Flow

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)

Create SLA Definition

// 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

// 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)

Query Task SLAs

// 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 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

// 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

Breach Notification Script (ES5)

// 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 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 Compliance Query (ES5)

// 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

Available Tools

| 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

Example Workflow

// 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

返回排行榜