mcpField
S
sla-management

sla-management

github.com/serac-labs其他7761 次安装9 周前更新
代码仓库

关于 sla-management

面向 ServiceNow 管理员和开发者的 SLA 管理技能,涵盖规则配置、任务计时、违约处理与合规报告,并提供 ES5 示例和 MCP 工具流程。

主要功能

  1. 01创建和配置 SLA 定义
  2. 02查询任务 SLA 记录与状态
  3. 03暂停和恢复 SLA 计时
  4. 04处理违约通知与升级
  5. 05计算 SLA 合规率

适用场景

  1. 01设定响应与解决时限
  2. 02在外部等待期间暂停 SLA
  3. 03在违约前后通知团队
  4. 04按日期范围检查合规率

MCP 相关

介绍如何使用 ServiceNow MCP 工具查找 SLA 定义、查询任务 SLA 记录、测试脚本和创建业务规则。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/serac-labs/serac --skill sla-management

安装后在 Claude Code 中输入/sla-management确认已加载。

详细介绍

ServiceNow 的 SLA 管理

SLA(服务级别协议)管理用于跟踪并确保履行服务承诺。

SLA 组件

组件表用途
SLA 定义contract_slaSLA 规则和条件
任务 SLAtask_sla任务上的 SLA 实例
SLA 工作流wf_workflowSLA 违约通知
SLA 计划cmn_schedule工作时间定义

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

SLA 定义(ES5)

创建 SLA 定义
// 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 条件说明
// 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"

任务 SLA 操作(ES5)

查询任务 SLA
// 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"),
  )
}
检查 SLA 状态
// 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",
}
暂停/恢复 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 工作流

违约通知脚本(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 升级规则
// 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 报告

SLA 合规性查询(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 工具集成

可用工具
工具用途
snow_artifact_manage (action='find')查找 SLA 定义
snow_query_table查询 task_sla 记录
snow_execute_script测试 SLA 脚本
snow_create_business_rule创建 SLA 触发器
示例工作流
// 1. Find existing SLAs
await snow_artifact_manage({
  action: "find",
  type: "contract_sla",
  query: "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({
  script:
    'var stats = getSLAComplianceRate("P1 Response", gs.beginningOfThisMonth(), gs.endOfThisMonth()); gs.info(JSON.stringify(stats));',
})

最佳实践

  1. 名称清晰 - “P1 Incident Response 15min”
  2. 工作时间 - 使用适当的计划
  3. 暂停条件 - 等待外部处理时暂停
  4. 升级 - 违约前发出通知
  5. 指标 - 跟踪合规率
  6. 测试 - 使用各种场景进行测试
  7. 文档 - 记录 SLA 条款
  8. 仅使用 ES5 - 不使用现代 JavaScript 语法

评论

支持 Markdown