メインコンテンツへスキップ
見出し画像

インシデント管理モジュールの自動設定構成


    インシデントを1件保存するたびに、裏では多数の処理が動きます。担当グループを変えると担当者が消える。優先度を上げると作業メモが必須になる。クローズすると作業タスクが一斉に閉じる。どれもコードを書いた覚えがないのに起きます。Australia の PDI をデフォルト設定のまま開き、それぞれの処理が何をしているかを確かめました。

    検証環境:Australia PDI / OOTB / 2026-08-31 確認

    押さえておくこと

    • ビジネスルールの中心は、状態の記録・親子の同期・他プロセスへの連鎖

    • state と incident_state は order 0 と order 1,000,000 の2件のルールで相互に同期される

    • クライアントスクリプトは入力の補助、UIポリシーは条件による表示の切り替えを担う

    • データポリシーは画面外からの投入にも効き、解決情報の必須化に使われている

    • 通知のうちインシデント運用に関わるのは一部で、残りはプラットフォーム全体の連絡

    ビジネスルールが動くタイミング

    ビジネスルールは、実行されるタイミングで4種類に分かれます。


    画像


    画像


    画像

    before が24件と最多です。データベースへ書き込む前に値を補正したり、条件によっては保存そのものを中断したりします。

    after の10件は、書き込みが終わってから動きます。他のレコードを更新する処理が中心です。親インシデントの件数を数え直す、作業タスクをまとめて閉じる、といった連鎖がここで起きます。

    display の3件は、フォームを画面に出す前に実行されます。VIP利用者かどうかを判定してスクラッチパッドに載せる処理などです。画面側のスクリプトが参照する値を、あらかじめ用意します。

    g_scratchpad は、サーバ側からブラウザ側へ値を渡す入れ物です。VIP判定がこの方式を使う理由は、判定に sys_user 側の項目が必要だからです。ブラウザから毎回問い合わせると遅くなるため、フォームを出す前にサーバ側で調べて渡します。

    主要なビジネスルールの処理内容

    38件のうち、動きが分かりやすい19件を挙げます。


    画像


    画像

    いくつかを詳しく見ます。

    mark_resolved(before / order 100)

    条件は incident_state == RESOLVED || incident_state == CLOSED です。状態が解決になったとき、次の処理が実行されます。

    • resolved_by が空なら、操作しているユーザーを入れる

    • resolved_at が空なら、現在時刻を入れる

    • opened_at と resolved_at の差から、解決までの所要時間を計算する

    • 実時間(calendar_stc)と営業時間(business_stc)の両方を求める

    担当者が「解決」を押すだけで、誰が・いつ・何時間かかったかが記録されます。手で入力する項目ではありません。

    mark_closed(before / order 100)

    条件は incident_state == CLOSED || incident_state == CANCELED。

    • active を false にする

    • closed_by と closed_at を入れる

    • クローズまでの所要時間を計算する

    active が false になると、一覧の既定フィルタ(active=true)から外れます。クローズしたインシデントが一覧から消えるのは、この1行によるものです。

    Caller Close(before / order 200)

    条件は caller_id == gs.getUserID() かつ状態が Resolved か Closed に変わったときです。利用者が自分で解決を報告した場合に動きます。

    • close_code が空なら「Resolved by caller」を入れる

    • close_notes が空なら「Closed by Caller」を入れる

    利用者はポータルから解決コードを選べません。そこで自動的に「利用者が解決した」と記録します。この仕組みがあるおかげで、解決コードの集計に空欄が混ざりません。

    Abort changes on group(before / order 100)

    フィルタは assigned_toISNOTEMPTY^assignment_groupVALCHANGES^assignment_groupISNOTEMPTY です。担当者が入ったまま担当グループを変えたときに動きます。

    処理は sys_user_grmember(グループのメンバー表)を検索し、その担当者が新しいグループに所属しているかを調べます。所属していなければエラーメッセージを出し、保存そのものを中断します。

    「担当グループを変えたら保存できなくなった」という相談の答えがここにあります。担当者を先に空にするか、その人をグループに追加する必要があります。

    Prevent Recursion of Parent Incident(before / order 100)

    RecursionTester を使い、親子関係がループしないかを判定します。ループする場合の動きは3つです。

    • setAbortAction(true) で保存を中断する

    • parent_incident の欄に「Invalid Parent Incident」とエラーを表示する

    • 画面上部に「選択した親インシデントがこのレコードへ戻ります(再帰ループ)」と出す

    AをBの子に、BをAの子に設定する操作を止めるためのルールです。

    Reopen Count(before / order 9,000)

    処理は1行だけでした。

    current.reopen_count += 1;

    条件は new Incident(current).hasReopened()。再オープンと判定されたとき、カウンタを1増やします。この値が再オープン率の集計に使われます。

    Incident State Change to In Progress(before / order 100)

    フィルタが具体的です。

    commentsVALCHANGES ^ state=3 ^ hold_reason=1 ^ caller_idDYNAMIC(ログイン中のユーザー)

    読み下すと「利用者待ちで保留中のインシデントに、その利用者本人がコメントを書いたとき」です。この条件が揃うと、状態を In Progress へ戻します。

    利用者が返答すれば、担当者が操作しなくても保留が解けます。返答に気づかず放置される事態を防ぐ設計です。

    他のテーブルへ連鎖する処理

    インシデントの保存が、別のテーブルの更新を引き起こす場合があります。after のビジネスルールが担当します。

    Cascade closure of Incident Tasks(after / order 100)

    フィルタは stateCHANGESTO7^ORstateCHANGESTO8。Closed か Canceled に変わったときだけ動きます。処理の流れは4段階です。

    1. プロパティ com.snc.incident.incident_task.closure が true かを確認する

    2. TaskStateUtil から「非アクティブとみなす状態」の一覧を取得する

    3. incident_task を検索し、このインシデントに紐づくものを集める

    4. まだ非アクティブでない作業タスクを、まとめて閉じる

    親を閉じれば、ぶら下がる作業タスクが自動で片付きます。閉じ忘れた作業タスクが残る事態を防ぎます。

    Update Problem Incident Count(after / order 100)

    条件は current.problem_id.changes()。処理は GlideAggregate で問題に紐づくインシデントを数え、問題レコードの件数欄を更新します。

    変更前の問題(previous.problem_id)と変更後の問題の両方を数え直す作りです。付け替えたとき、どちらの件数も正しくなります。

    Update Parent Incident Count(after / order 200)

    親インシデントが持つ子の件数(child_incidents)を数え直します。こちらも変更前後の両方を更新します。

    Incident Create Knowledge(after / order 100)

    条件は「incident_state が CLOSED に変わり、かつ knowledge が true」。処理は次の分岐から始まります。

    1. プロパティ glide.knowman.submission.workflow を確認する

    2. true なら、承認ワークフローへ提出する

    3. false なら、直接 kb_knowledge に下書きを作る

    作られる記事の中身も決まっています。

    • source:元のインシデントの sys_id

    • short_description:インシデントの短い説明をそのまま使う

    • text:追加コメント(comments)の内容を本文にする

    • workflow_state:draft(下書き)

    利用者向けコメントが記事本文になる点が実務に効きます。作業メモではなく、利用者に向けて書いた説明が使われます。

    ナレッジ化を運用に組み込むなら、クローズ前の追加コメントに解決手順を書く習慣をつけます。作業メモに詳しく書いても、記事には反映されません。

    incident events(after / order 50)

    イベントをキューへ積むルールです。処理を読むと、3種類を出し分けています。

    • 新規作成のとき:incident.inserted

    • 更新でコメントが変わったとき:incident.commented

    • 更新でコメント以外が変わったとき:incident.updated

    通知が飛ぶかどうかは、このルールが出すイベント次第です。order 50 で after の中では最も早く動き、その後に通知が処理されます。

    incident autoclose(after / order 100)

    スケジュール実行されるルールです。処理は5段階に分かれます。

    1. プロパティ glide.ui.autoclose.time から日数を取得する

    2. 現在時刻からその日数を引いた時刻を求める

    3. incident_state が RESOLVED のインシデントを検索する

    4. com.snc.incident.autoclose.basedon.resolved_at が true なら resolved_at、false なら最終更新日で絞る

    5. 該当するものを Closed へ変える

    基準日をプロパティで切り替えられる設計です。解決後に問い合わせが入って作業メモを追記した場合、解決日基準なら予定どおり閉じ、更新日基準なら遅れます。

    Set incident origin(before / order 999)

    フィルタは origin_tableISEMPTY^caused_byISNOTEMPTY。処理は2行です。

    current.origin_table = 'change_request';
    current.origin_id = current.caused_by;

    変更が原因で起きた障害を記録するとき、どの変更から来たかを origin_table と origin_id に残します。

    state と incident_state の同期

    インシデントには状態を表す項目が2つあります。state(task から継承)と incident_state(incident 固有)です。


    画像

    ルール名orderフィルタ処理Copy State to Incident State0stateVALCHANGESstate の値を incident_state へ写すCopy Incident State to State1,000,000incident_stateVALCHANGESincident_state の値を state へ写す

    order が 0 と 1,000,000 という両極端の値になっています。すべてのルールの最初と最後に挟み込む設計です。

    途中のルールがどちらの項目を更新しても、最後に必ず同期が取られます。自社でビジネスルールを足すとき、片方の項目だけを書き換えると、もう一方の値に戻されます。

    クライアントスクリプトの画面での処理

    ブラウザ側で動くスクリプトは24件あり、うち18件が有効でした。


    画像


    画像

    動きが分かりやすいものを見ます。

    (BP) Set Location to User(onChange / caller_id)

    利用者を選ぶと、その人の所属拠点を location へ自動で入れます。利用者を空にすると、location も一緒に消えます。入力の手間を減らす処理です。

    Empty assigned_to on group change(onChange / assignment_group)

    担当グループを変えると、担当者の欄を空にします。前のグループのメンバーが残ったままにならないための処理です。

    サーバ側の Abort changes on group と対になっています。画面では自動で空にし、それでも不整合が残る場合はサーバ側で保存を止めます。

    Worknotes mandatory onChange of priority(onChange / priority)

    優先度を変えると、作業メモが必須になります。「なぜ優先度を変えたか」を記録させる仕組みです。値を元に戻すと、必須は解除されます。

    Highlight VIP Caller(onChange / caller_id)

    VIP登録された利用者を選ぶと、Caller 欄の背景色を変えて目立たせます。スマートフォン版(Highlight VIP Caller (Smartphone))は色ではなくアイコンを付けます。同じ目的でも画面ごとに実装が分かれています。

    (BP) Hide Attachment Link when Closed(onLoad)

    処理は3行だけでした。

    if (g_form.getValue('incident_state') == '7' || g_form.getValue('state') == '7')
        g_form.disableAttachments();

    Closed のインシデントでは添付の追加を止めます。ACLで書き込みを止めるだけでなく、画面上でも操作させない作りです。

    (BP) Hide Choice - Closed(onLoad)

    itil_admin を持っていないユーザーには、状態の選択肢から Closed を隠します。担当者が直接クローズせず、Resolved で止める運用を促す処理です。

    (BP) Close Mandatory on Close or Resolve(onSubmit)

    Resolve か Close のボタンを押したときだけ動きます。解決コードと解決メモが空なら、保存を止めます。

    Clear Offering on changing Service(onChange / business_service)

    サービスを変えると、サービスオファリングの選択を消します。親を変えたのに子が古いまま残る事態を防ぎます。

    UIポリシーの制御対象

    UIポリシーは15件あり、すべてが有効でした。


    画像


    画像


    画像

    条件が具体的なものを挙げます。

    When state is On Hold the On hold reason field is visible

    条件は state=3。On Hold のときだけ保留理由の欄を表示し、必須にします。それ以外の状態では隠れます。

    Make the field 'Additional Comments' mandatory when the incident is on hold

    条件は hold_reason=1^state=3。利用者待ちで保留にするときだけ、追加コメントを必須にします。利用者へ何を依頼したかを記録させる仕組みです。

    Make fields read-only on close

    条件は incident_state=7^ORincident_state=8。クローズ済み・取り消し済みでは項目を読み取り専用にします。ACLと二重に守る構成です。

    (SOW) Make Parent Incident mandatory

    条件は close_code=Duplicate。重複としてクローズするとき、親インシデントの指定を必須にします。どのインシデントと重複しているかを残させます。

    Priority is managed by Data Lookup - set as read-only

    条件なし(常時適用)。優先度を読み取り専用にします。影響度と緊急度から自動で決まる項目なので、直接編集させない方針です。

    UIポリシーの多くは reverse_if_false が true でした。条件から外れると、設定が自動で戻ります。「一度必須にしたら解除されない」という事態を避ける設定です。

    データポリシーによる解決情報の必須化

    画面を問わず効く必須制御は1件でした。


    画像

    Make close info mandatory when resolved or closed という定義の中身です。

    項目設定条件stateIN6,7(Resolved または Closed)必須にする項目close_code と close_notes逆適用(reverse_if_false)trueインポートセットに適用trueSOAP に適用trueUI にも強制true

    インポートセットにも SOAP にも適用される設定です。REST API から状態を Resolved にするときも、解決コードと解決メモを渡さなければエラーになります。

    UIポリシーは画面でしか効きません。データポリシーはどの経路でも効きます。解決情報だけがデータポリシーで守られているのは、記録として欠かせない項目だからです。

    通知の送信条件と宛先

    有効な通知は23件でした。うちインシデント運用に関わるのは14件です。


    画像


    画像

    件名を見ると、何が送られるかが分かります。

    通知件名Incident was openedIncident ${task_effective_number} was createdIncident assigned to meIncident ${number} has been assigned to youIncident assigned to my groupIncident ${number} has been assigned to group ${assignment_group}Incident commented for ITILIncident ${number} - comments addedIncident worknoted for ITILIncident ${number} - Work notes addedIncident Priority Raised${number} priority raised to ${priority}Incident resolved${task_effective_number} was resolvedIncident closedIncident ${number} was closed

    宛先の設計も条件から読み取れます。

    • 担当者へ送るもの:割り当て時、コメント追記時、作業メモ追記時、優先度上昇時

    • 利用者へ送るもの:起票時、解決時、クローズ時、コメントが付いたとき

    • グループへ送るもの:担当者が空のままグループが変わったとき

    Incident assigned to my group の条件が具体的です。

    assigned_toISEMPTY ^ assignment_groupVALCHANGES ^ assignment_groupISNOTEMPTY

    「担当者が決まらないままグループが変わったとき」だけグループ全員へ送ります。担当者が決まっていれば、その人だけに届きます。

    Incident commented and state changed はさらに条件が細かく、commentsVALCHANGES^stateCHANGESFROM3^stateCHANGESTO2 でした。保留から進行中へ戻ったときの連絡です。

    通知の起点になるイベントも登録されています。


    画像

    インシデント運用と無関係な通知

    通知を1件ずつ見ると、インシデント管理とは別の目的のものが混ざっていました。


    画像

    テキスト索引の完了、システムのアップグレード、パスワードリセットの完了。どれもプラットフォーム全体の連絡で、collection が incident になっているだけです。

    「incident の通知が23件ある」と数えると、実態より多く見えます。運用で見直す対象は14件です。導入時の確認作業を見積もるとき、この違いが効きます。

    UIアクションの処理内容

    フォーム上のボタンは23件が有効でした。


    画像


    画像

    主要な3つの中身を見ます。

    Resolve

    表示条件は new global.IncidentUtils().canResolveIncident(current)。押すと次を実行します。

    g_form.setValue('incident_state', 6);
    g_form.setValue('state', 6);
    g_form.setValue('resolved_by', g_user.userID);

    incident_state と state の両方を設定している点に注目してください。同期のビジネスルールがあるにもかかわらず、画面側でも両方を明示的に入れています。

    Close

    サーバ側で実行されます。

    current.incident_state = IncidentState.CLOSED;
    current.state = IncidentState.CLOSED;
    current.update();

    Reopen

    追加コメントが空なら必須に設定してから送信します。再オープンの理由を必ず残させる作りです。

    表示条件が IncidentUtils のメソッド呼び出しになっている点も特徴です。条件式ではなくスクリプトで判定しているため、「ボタンが出ない」理由を調べるときは Script Include の中身まで見る必要があります。

    1回の保存で処理が動く順序

    ここまでの仕組みが、保存ボタンを1回押したときにどう重なるかを整理します。


    画像

    保存から通知までは、次の順序で処理が進みます。

    1. クライアントスクリプトとUIポリシー:ブラウザ側で入力を制御する

    2. データポリシー:画面を問わず必須をチェックする

    3. ACL:書き込む権限があるかを判定する

    4. ビジネスルール(before):値を補正する、条件次第で中断する

    5. データベースへ書き込み

    6. ビジネスルール(after):他レコードを更新し、イベントを発行する

    7. 通知:イベントを受けてメールを送る

    この順序が分かると、障害の切り分けが速くなります。画面で止まるならクライアント側、保存を押した瞬間に止まるならデータポリシーかACL、保存できたのに後続が動かないなら after のルールです。

    独自の処理を追加するときの order 設計

    既存38件の order を見ると、値の付け方に規則があります。

    order の範囲使われ方例0最初に必ず動かすCopy State to Incident State50〜200通常の処理mark_resolved / Update Problem Incident Count999〜1,100他の処理の後に動かすSet incident origin / Incident State Active on Assignment9,000かなり後Reopen Count1,000,000最後に必ず動かすCopy Incident State to State

    独自のルールは、既存が使っていない帯(500番台や1,500番台)を選ぶのが安全です。アップグレードで標準ルールの order が変わっても、自社のルールが巻き込まれません。

    order の設計とあわせて、命名規則も決めておきます。標準のルールには接頭辞がないため、自社のものに [社名] や Custom - を付けると一覧で区別しやすい形。38件の標準ルールに混ざると、どれが自社製か分からなくなります。

    同じ order のルールが複数ある場合、実行順は保証されない点にも注意が要ります。順序に依存する処理を書くなら、必ず異なる値を割り当ててください。

    一覧の表示時に実行される処理

    38件のうち1件は query で動きます。incident query という名前のルールです。

    query のビジネスルールは、レコードを取得するたびに実行されます。一覧を開いたとき、レポートを描くとき、REST API で読むとき。すべての読み取りに条件が足されます。

    用途はデータの絞り込みです。ドメイン分離や、特定条件のレコードを隠す処理に使われます。ACLと似た働きをしますが、ACLが「見えるかどうか」を判定するのに対し、query は検索条件そのものを書き換えます。

    ここに重い処理を書くと、一覧の表示が遅くなります。1件のレコードにつき1回ではなく、検索1回につき1回動くため、影響範囲が広い箇所です。

    無効になっている定義

    有効なものだけを見ていると、止まっている処理を見落とします。

    種別有効無効ビジネスルール381クライアントスクリプト186UIポリシー150UIアクション233通知231

    無効なクライアントスクリプト6件のうち3件は Sample: で始まる学習用のものでした。残る3件は Make Mandatory、Remove Priority 1、Knowledge Sticky On です。

    Remove Priority 1 は名前から用途が推測できます。優先度1を選べないようにする処理でしょう。有効化する前に、中身を読んで自社の運用に合うかを確認します。

    実機で気づいたこと

    症状:state を更新するビジネスルールを足したのに、値が元に戻ります。

    原因:Copy Incident State to State が order 1,000,000 で最後に実行され、incident_state の値で state を上書きするためです。

    現場での回避策:状態を変える処理では、state と incident_state の両方を更新します。標準の Resolve ボタンも、画面側で両方を明示的に設定していました。


    症状:Update Problem Incident Count の条件が current.problem_id.changes() になっています。ところが Australia のデフォルト環境の incident には、problem_id が存在しません。

    原因:他のプラグイン構成向けのルールが、そのまま同梱されています。存在しない項目を参照する条件は成立しないため、このルールは実質動きません。

    現場での回避策:問題との紐づけ件数を追いたい場合、この標準ルールに頼らず、自社の連携方法に合わせた処理を作ります。まず problem_id が自分の環境にあるかを確認します。


    症状:担当グループを変えようとすると、エラーで保存できません。

    原因:Abort changes on group が、担当者が新しいグループのメンバーかを sys_user_grmember で確認しています。所属していなければ setAbortAction で保存を中断します。

    現場での回避策:担当者を先に空にしてからグループを変えます。画面側の Empty assigned_to on group change が自動で空にしますが、直接データを更新する経路では働きません。


    症状:通知が23件あると数えたのに、運用で見直すべきものが見つかりません。

    原因:23件のうち9件は、テキスト索引の完了・システムのアップグレード・パスワードリセットなど、インシデント運用と無関係な通知でした。

    現場での回避策:collection=incident で数えた件数をそのまま扱いません。件名とイベント名を見て、インシデント運用に関わる14件だけを対象にします。

    実務で順番に検討する箇所

    自動処理を調整するとき、次の順序で確認します。


    画像
    1. 既存38件の把握:order 順に並べて、自社の処理を差し込む位置を決める

    2. 状態の同期:state と incident_state の両方を更新する前提で設計する

    3. before か after か:値を補正するなら before、他レコードを更新するなら after

    4. クライアント側かサーバ側か:見た目だけならUIポリシー、計算が要るならクライアントスクリプト

    5. API経由の制御:画面外からの投入も止めるならデータポリシー

    6. 通知の取捨:インシデント運用に関わる14件を1つずつ確認する

    7. 無効なスクリプトの扱い:サンプル3件を残すか削除するかを決める

    用語

    • OOTB:Out of the Box。プラグイン追加やカスタマイズを行っていない、製品のデフォルト状態

    • PDI:Personal Developer Instance。ServiceNow が無償で提供する個人検証用インスタンス

    • ビジネスルール:サーバ側で動く処理。保存の前後や取得時に実行される

    • order:同じタイミングのルールを実行する順序。小さいほど先に動く

    • g_scratchpad:display のビジネスルールからクライアントスクリプトへ値を渡す入れ物

    • (BP):Best Practice プラグイン由来のスクリプトに付く接頭辞

    検証範囲とおことわり

    • 検証環境:Australia PDI(patch3)/ OOTB / 2026-08-31 確認

    • 件数はすべて OOTB の定義の数です。本番環境やカスタマイズ済み環境では異なります

    • スクリプトの内容は先頭部分を読んで動きを整理したものです。全文の網羅的な検証は行っていません

    • 実際にレコードを保存して処理の順序を観測する検証は行っていません

    • 通知の本文テンプレートは確認していません

    • Update Problem Incident Count が実際に動かないことは、条件式から判断しています

    付録:自分の環境で確認するときのURL

    • ビジネスルールのタイミング別:/sys_script_list.do?sysparm_query=collection=incident^active=true^GROUPBYwhen

    • ビジネスルールを order 順に:/sys_script_list.do?sysparm_query=collection=incident^active=true^ORDERBYorder

    • クライアントスクリプト:/sys_script_client_list.do?sysparm_query=table=incident^GROUPBYtype

    • UIポリシー:/sys_ui_policy_list.do?sysparm_query=table=incident

    • UIポリシーのアクション:/sys_ui_policy_action_list.do?sysparm_query=ui_policy.table=incident

    • データポリシー:/sys_data_policy2_list.do?sysparm_query=model_table=incident

    • データポリシーのルール:/sys_data_policy_rule_list.do

    • 通知:/sysevent_email_action_list.do?sysparm_query=collection=incident^active=true

    • UIアクション:/sys_ui_action_list.do?sysparm_query=table=incident^active=true

    • イベント定義:/sysevent_register_list.do?sysparm_query=nameLIKEincident

    関連記事

     
     
    ServiceNowのPDI(Personal Developer Instance)を実機で観察して、Noteに記事を書いています 実装・運用・教育の現場視点で淡々と記録中です リクエストがあればその記事も書きます 個人の観察日記です

    あなたへのおすすめ