mcpField
S
sla-management

sla-management

github.com/serac-labsその他7761 回インストール9 週間前に更新
リポジトリ

sla-management について

ServiceNow の SLA を管理するスキルです。定義やタスクのタイマー、違反対応、遵守状況のレポートを扱い、管理者や開発者向けに ES5 の例と MCP ツールの手順を示します。

主な機能

  1. 01SLA 定義の作成と設定
  2. 02タスク SLA の記録と状態の照会
  3. 03SLA タイマーの一時停止と再開
  4. 04違反通知とエスカレーションの処理
  5. 05SLA 遵守率の算出

活用シーン

  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_tabletask_sla レコードを照会
snow_execute_scriptSLA スクリプトをテスト
snow_create_business_ruleSLA トリガーを作成
ワークフローの例
// 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 構文は使用しません

コメント