sla-management について
ServiceNow の SLA を管理するスキルです。定義やタスクのタイマー、違反対応、遵守状況のレポートを扱い、管理者や開発者向けに ES5 の例と MCP ツールの手順を示します。
主な機能
- 01SLA 定義の作成と設定
- 02タスク SLA の記録と状態の照会
- 03SLA タイマーの一時停止と再開
- 04違反通知とエスカレーションの処理
- 05SLA 遵守率の算出
活用シーン
- 01応答時間と解決時間の目標設定
- 02外部待ちの間の SLA 停止
- 03違反前後のチームへの通知
- 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_sla | SLA のルールと条件 |
| タスク SLA | task_sla | タスク上の SLA インスタンス |
| SLA ワークフロー | wf_workflow | SLA 違反の通知 |
| 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));',
})
ベストプラクティス
- 明確な名前 - 「P1 Incident Response 15min」
- 営業時間 - 適切なスケジュールを使用します
- 一時停止条件 - 外部からの応答待ちの間は一時停止します
- エスカレーション - 違反前に通知します
- メトリクス - 遵守率を追跡します
- テスト - さまざまなシナリオでテストします
- ドキュメント - SLA の条件を文書化します
- ES5 のみ - 最新の JavaScript 構文は使用しません
コメント
Markdown 対応