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

ServiceNowの深夜のアラートは誰が受ける? On-Call Scheduling(cmn_rota)の当番表を実機で読む


    深夜に上がった重大インシデントが、結局どの担当者に飛ぶのか分からない。当番を交代したはずなのに、前任者へ通知が届く。こうした相談の裏には、ServiceNowの当番表がテーブルとして3階層に分かれている事情があります。cmn_rota(当番表の箱)・cmn_rota_roster(Primary/Secondaryの階層)・cmn_rota_member(メンバーと順番)の3つです。最終的には、営業時間と同じcmn_scheduleテーブルに展開されて「今の当番」が決まります。Zurich PDIのOOTBデータで、この3階層と展開先を実機で確認しました。

    検証環境:Zurich PDI / OOTB / 2026-08-09 確認


    結論:当番表は3階層のテーブルとcmn_scheduleへの展開で決まる

    全体像を先に示します。

    • 当番表はcmn_rota(当番表の箱・12件)、cmn_rota_roster(Primary/Secondaryの階層・21件)、cmn_rota_member(メンバーと順番・59件)という3階層のテーブルに保存されています。

    • 同じ名前のorderフィールドが2箇所にありますが、意味は別です。roster.orderはエスカレーション順位、member.orderはローテーション位置を表します。

    • 「今、誰が当番か」というカレンダーは、当番専用のテーブルではなく、営業時間と同じcmn_scheduleにrotation/roster型として展開されています。


    画像

    グループ(sys_user_group)が持つ当番表(cmn_rota)の下に、Primary/Secondaryの階層(cmn_rota_roster)がぶら下がります。その階層に当番のメンバー(cmn_rota_member)が並び、メンバーはさらにsys_userを参照します。


    On-Call Scheduling(オンコール・ローテーション)とは何か

    ServiceNowのオンコール・スケジューリングは、「いつ・どのグループの・誰が当番か」をカレンダーとして定義する仕組みです。定義した当番表は、Incidentのエスカレーションや通知から参照されます。夜間のインシデントで「今の当番」へ自動通知されるのも、この当番表が「今は誰の番」と教えているからです。

    公式のConfigure or update an On-Call schedule(Zurich)に、当番表(Rota)をグループとスケジュールから作る手順が説明されています。

    テーブル定義は、次のURLで確認できます(先頭の<YourInstance>は自分のインスタンスに置き換えてください)。

    https://<YourInstance>/sys_db_object_list.do?sysparm_query=nameSTARTSWITHcmn_rota

    当番表はどう3階層に分かれている?(cmn_rota / cmn_rota_roster / cmn_rota_member)

    オンコールに関係するテーブルは、「当番表(箱)」「階層(順位)」「メンバー(人)」の3つに分けて見ると整理できます。3テーブルともsuper_classが空(ルート基底テーブル)で、taskなどを継承する構造ではありません。継承なしの独立系です。

    • cmn_rota(label: Shift)…当番表本体。group(→sys_user_group)で「どのグループの当番表か」を持ち、based_on(→cmn_schedule)は稼働の土台となる営業時間カレンダー(例24 x 7)への参照です。固有フィールドは27。

    • cmn_rota_roster(label: Roster)…当番の階層。rota(→cmn_rota)で親の当番表を参照し、orderでPrimary(1)/Secondary(2)/Tertiary(3)の順位を持ちます。固有フィールドは25。

    • cmn_rota_member(label: On-call Member)…メンバー。roster(→cmn_rota_roster)とmember(→sys_user)でロースターと人を結び、orderで「ローテーションの何番目か」を持ちます。固有フィールドは12。


    画像

    当番表(cmn_rota)は1つの箱、ロースター(cmn_rota_roster)はその中の順位の段、メンバー(cmn_rota_member)はその段に並ぶ人です。1つの当番表に複数のロースターが付き、1つのロースターに複数のメンバーがぶら下がります。この構造が「Primaryが無理ならSecondary」「メンバーで週替わり」を表現する土台です。

    実機で当番表のフォームを開くと、この構造がそのまま見えます。


    画像

    当番表(cmn_rota)はグループ単位でどう設定される?

    当番表は、グループ(sys_user_group)に対して1つ以上作られます。今回のPDI(Zurich / OOTB)のcmn_rota 12件は、いずれもグループに紐づいていました。Hardware / Network / Service Desk / Application Development / ITSM App-Dev / Nimsoft deskなどです。

    実機のRotas一覧を見ると、グループごとに当番表が並んでいるのが分かります。


    画像

    各当番表は、based_onで営業時間カレンダー(cmn_schedule)を土台にします。今回のPDIでは、Hardware系の多くが24 x 7でした。Office Hours / Working HoursはWorkday 8:00 - 5:00やWorkday 9:00 - 5:00を土台にしていました。

    当番表本体の状態を表すstateフィールドは、choiceがdraft(Draft)の1値しか定義されていません。今回のPDIでは、12件すべてでstateは空(未設定)でした。send_reminders(当番リマインダ送信)は12件すべてでtrueです。use_custom_escalationがtrueなのはHardware (US)の1件だけでした。

    • state(State)…choiceはdraft 1値のみ。実データは空。

    • send_reminders(Send on-call reminders)…全12件true。

    • use_custom_escalation(Use custom escalation)…1件(Hardware (US))のみtrue。

    https://<YourInstance>/cmn_rota_list.do?sysparm_query=ORDERBYgroup

    Primary/Secondaryの順番はどこで決まる?(roster.orderとrotation_interval_type)

    当番表の中には、Primary / Secondary / Tertiaryという階層(ロースター)が入ります。これが「Primaryが応答しなければSecondaryへ」というエスカレーションの順位になります。

    order という名前のフィールドは2か所にあり、それぞれ意味が違います。名前は同じでも中身は別物です。

    • cmn_rota_roster.order…ロースターの順位。1=Primary / 2=Secondary / 3=Tertiaryのように、エスカレーションでどの段から呼ぶかを表します。

    • cmn_rota_member.order…メンバーのローテーション位置。同じロースター内で当番を回す順番(0, 1, 2…)を表します。


    画像

    今回のPDI(Zurich / OOTB)のcmn_rota_roster 21件は、ほとんどがPrimary / Secondaryで、Tertiaryを持つのはGlobalの1件だけでした。rotation_interval_type(当番が交代する周期)は21件すべてがweekly(毎週)で、daily(毎日)は0件でした。


    画像

    ロースターが「いつ交代するか」を決めるのは2つのフィールドです。rotation_interval_type(daily / weekly)とrotation_start_dow(交代開始曜日:1=Sunday〜7=Saturday)です。今回のPDIでは全件weeklyでしたが、dailyを選べば毎日交代の当番表も作れます。


    画像
    https://<YourInstance>/cmn_rota_roster_list.do?sysparm_query=ORDERBYrota^ORDERBYorder

    公式のConfigure a roster(Zurich)に、ロースターの命名(Primary/Secondary)とローテーション間隔の設定方法が説明されています。


    誰が何番目に回る? cmn_rota_memberのorderと実際のローテーション

    ロースターの中に並ぶのが、メンバー(cmn_rota_member)です。member(→sys_user)で人を指し、orderで「ローテーションの何番目か」を持ちます。

    今回のPDI(Zurich / OOTB)のcmn_rota_memberは59件でした。例えばHardware (US)のロースターを見ると、Primaryの1番目がBeth Anglin、2番目がDavid Loo。Secondaryの1番目がDavid Loo、2番目がBeth Anglinでした。同じ2人がPrimaryとSecondaryの両方に入り、段によって順番が入れ替わる構成です。折り返しの当番です。


    画像

    メンバーの主なフィールドは次のとおりです。


    画像
    • member(Member → sys_user)…当番に入るユーザー。

    • roster(Roster → cmn_rota_roster)…所属するロースター。

    • order(Order)…ロースター内のローテーション順(0, 1, 2…)。

    • from / to(From / To)…メンバーの有効期間。期間を区切って交代要員を入れられます。

    • rotation_schedule(Rotation schedule → cmn_schedule)…このメンバーの当番期間を表す生成スケジュール(後述)。

    実機の辞書一覧を見ると、これらのフィールドと参照先が並んでいます。公式のData dictionary tables(Zurich)にも、sys_dictionaryでフィールド定義を管理する仕組みが説明されています。


    画像
    https://<YourInstance>/sys_dictionary_list.do?sysparm_query=name=cmn_rota_member^elementISNOTEMPTY

    「今、誰が当番か」はどこで解決される? cmn_scheduleへの展開

    オンコールの3テーブルが持つのは「設定」までです。「誰がいつ当番か」という実際のカレンダーは、専用テーブルを持たず、cmn_schedule(営業時間と同じテーブル)に展開されていました。


    画像

    今回のPDI(Zurich / OOTB)で確認した対応は、次のとおりでした。

    • cmn_rota_memberは59件すべてがrotation_schedule(→cmn_schedule)を持っていました。

    • cmn_schedule側でtype=rotationのレコードは59件でした。メンバー59件とrotation型スケジュール59件が一致します。各メンバーの当番期間が「Hardware: Beth Anglin: Primary」のような名前のスケジュールとして1件ずつ生成されているわけです。

    • 同様に、cmn_schedule側でtype=rosterのレコードは12件で、当番表(cmn_rota)12件と一致しました。

    オンコールの最終的な「いつが当番か」は、SLAの営業時間と同じcmn_scheduleテーブルにrotation / roster型として落ちます。当番カレンダーを調べたいときに「専用テーブルを探しても見つからない」のはこのためです。探す場所が違ったのです。cmn_scheduleのtypeで絞るのが正解でした。

    https://<YourInstance>/cmn_schedule_list.do?sysparm_query=type=rotation
    https://<YourInstance>/cmn_schedule_list.do?sysparm_query=type=roster

    cmn_scheduleのtype分布は、営業時間を扱った別記事でも同じ数字(rotation 59 / roster 12)を確認しています。本記事のオンコール側(member 59 / rota 12)と表裏で一致する数字です。


    応答がなければ誰に回す? カスタムエスカレーション(escalation_set / esc_step_def)

    オンコールは「誰が当番か」だけでなく、「応答がなければ次に誰へ」というエスカレーションの仕組みも持っています。標準ではrosterのorder(Primary、Secondary…の順)で呼び出す設計です。use_custom_escalation=trueの当番表なら、独自のエスカレーション手順を組めます。


    画像

    今回のPDI(Zurich / OOTB)では、use_custom_escalation=trueの当番表はHardware (US)の1件のみでした。その下には次のテーブルが紐づいていました。

    • cmn_rota_escalation_set(Shift Escalation Set)… 3件:Hardware (US) - Default escalation set / High Priority Incident / Critical Incident。インシデントの重大度ごとに別の手順を用意していました。

    • cmn_rota_esc_step_def(Shift Escalation Step Definition)… 9件:各セットの「Notify Primary」「Notify Secondary」「Notify Group Manager」「Notify System Administrator」「Notify All Roster Members」といったステップ。

    • cmn_rota_escalation(Rotation Escalation)… 0件:これは実行(ログ)側で、今回のPDIでは発火実績がなく0件でした。実行ログはまだ空です。

    カスタムエスカレーションは、セット(重大度別)とステップ(誰に通知)の2段で組み立てます。標準のPrimary、Secondaryの順で足りない場合に、重大度に応じて呼ぶ相手と順序を変えられます。


    周辺機能はどれくらいある? Business Rule・UI Action・Notificationの実測

    オンコールの動きも、フィールド定義だけでは決まりません。保存時のサーバ側処理はBusiness rules(Zurich)、項目の出し分けはUI Policyが担います。


    画像

    特徴的なのは、cmn_rota側にUI Action(Zurich)が12件、Notification(Zurich)が3件ある点です。当番表は「今すぐ通知」「当番を見る」といった操作(UI Action)と、当番者へのメール通知(Notification)が厚くなっています。一方、メンバー(cmn_rota_member)は固有フィールド12と少なく、データの器に近い役割でした。役割分担がはっきりしています。

    ここで数えているのはオンコール側に直接紐づく設定だけです。実際のエスカレーション挙動は、Incident(assignment_group→当番表)や通知、On-CallのAPIとも合わさって決まります。オンコール単体だけを見て全体を判断しないようにします。

    Business Rules : https://<YourInstance>/sys_script_list.do?sysparm_query=collection=cmn_rota^active=true
    UI Policies    : https://<YourInstance>/sys_ui_policy_list.do?sysparm_query=table=cmn_rota
    UI Actions     : https://<YourInstance>/sys_ui_action_list.do?sysparm_query=table=cmn_rota

    実機で気づいたこと

    Hardware (US)の当番は、Beth AnglinとDavid Looの2人だけで組まれていました。最初はPrimary/Secondaryにそれぞれ別の担当者が並ぶと思っていましたが、実際はこの2人がPrimaryとSecondaryの間で順番を入れ替えて、お互いのバックアップになる構成です。担当者が少ないグループでは、大人数を並べるより、この折り返し構成の方が現実的だと分かりました。

    state フィールドは、choiceがdraft(Draft)の1値しか定義されていないのに、12件すべてで空でした。フィールドは存在するのに実質使われていない状態です。当番表が有効かどうかの管理には、代わりにActive(有効/無効フラグ)が使われているのだと考えられます。ここは推測です。

    当初は、当番のカレンダーを持つ専用テーブル(cmn_rota_scheduleのようなもの)があると想定していましたが、このPDIには存在しませんでした。当番の実体はcmn_schedule(営業時間と同じテーブル)にtype=rotation / rosterとして混ざっていて、テーブル名だけで探しても見つかりません。オンコールのカレンダーを調べるときは、まずcmn_scheduleのtypeで絞り込む発想を持っておくと早く辿り着けます。


    実務では何に使える? 通知トラブルを調査するときに見る場所

    深夜のインシデントが「想定と違う人に飛んだ」「通知が来ない」といったトラブルを調べるときは、次の順に見ると早く原因に辿り着けます。

    1. cmn_rota…対象グループの当番表を開き、based_on(土台のスケジュール)とuse_custom_escalationを確認する。

    2. cmn_rota_roster…rota配下をorder順に確認し、Primary/Secondaryのどちらが先に呼ばれる設定かを確認する。

    3. cmn_rota_member…roster配下のorderとfrom/toを確認し、「今の日時」がどのメンバーの担当期間かを特定する。

    4. cmn_schedule(type=rotation)…該当メンバーのrotation_scheduleを開き、実際のカレンダー表示で当番期間を目で確認する。

    use_custom_escalation=trueの当番表では、cmn_rota_escalation_set / esc_step_defも合わせて確認します。重大度に応じた独自の手順が、標準のPrimary→Secondary順の代わりに動いている可能性があるためです。


    さらに詳しく知りたい人へ


    まとめ

    当番表はcmn_rota(Shift)/ cmn_rota_roster(Roster)/ cmn_rota_member(On-call Member)の3階層です。今回のPDIでは12 / 21 / 59件でした。cmn_rotaはグループ単位で、based_on(→cmn_schedule)の営業時間を土台にします。orderは2種類あり、roster.orderがエスカレーション順位、member.orderがローテーション位置という違いです。「今、誰が当番か」は最終的にcmn_scheduleにrotation / roster型として展開されます。今回はmember 59=type=rotation 59、rota 12=type=roster 12と一致しました。カスタムエスカレーションはescalation_set(重大度別)とesc_step_def(誰に通知)の2段です。

    オンコールを調べるときは、まず当番表そのものを読みます。「このグループの当番表はどれか(group)」「ロースターの順位(Primary/Secondary)はどうか」「メンバーのorderでどう回るか」「交代周期はdailyかweeklyか」。そのうえで、当番カレンダーの実体はcmn_schedule(type=rotation/roster)に展開される、という対応関係を押さえておきます。通知が飛ばない・順番がずれるといった調査が、これで早くなります。

    用語

    • PDI…Personal Developer Instance(無料の検証用インスタンス)

    • OOTB…Out of the Box(初期設定のまま)

    • Rota / Shift(cmn_rota)…当番表(ローテーション)の本体。グループ単位

    • Roster(cmn_rota_roster)…当番表の中の階層(Primary/Secondary…)。orderでエスカレーション順位

    • On-call Member(cmn_rota_member)…ロースターに並ぶユーザー。orderでローテーション位置

    • rotation_schedule…メンバーの当番期間を表す生成スケジュール(cmn_schedule, type=rotation)

    • escalation set / step…カスタムエスカレーションのセット(重大度別)とステップ(通知先)

    実機で調べるときに開いたURL

    テーブル定義        : sys_db_object_list.do?sysparm_query=nameSTARTSWITHcmn_rota
    固有フィールド一覧   : sys_dictionary_list.do?sysparm_query=name=cmn_rota_member^elementISNOTEMPTY
    Rotas一覧           : cmn_rota_list.do?sysparm_query=ORDERBYgroup
    Rosters一覧         : cmn_rota_roster_list.do?sysparm_query=ORDERBYrota^ORDERBYorder
    交代周期グループ表示 : cmn_rota_roster_list.do?sysparm_query=GROUPBYrotation_interval_type
    当番スケジュール     : cmn_schedule_list.do?sysparm_query=type=rotation

    参考リンク


    検証環境と未検証範囲

    確認した範囲(PDI/Zurich/2026-08-09再確認のOOTBで取得。初回確認は2026-06-21):

    • cmn_rota / cmn_rota_roster / cmn_rota_memberの階層(いずれもルート基底)と固有フィールド数(27 / 25 / 12)

    • 主要フィールドと参照先(group→sys_user_group、based_on/schedule→cmn_schedule、rota→cmn_rota、roster→cmn_rota_roster、member→sys_user、rotation_schedule→cmn_schedule)

    • cmn_rota.state(draft1値)・rotation_interval_type(daily/weekly)・rotation_start_dow(7値)のchoices

    • レコード件数(12 / 21 / 59)とrotation_interval_type分布(全21 weekly)

    • rotation_schedule充足(59件)とcmn_scheduleへの展開(rotation 59 / roster 12)

    • エスカレーション件数(escalation_set 3 / esc_step_def 9 / escalation 0、custom利用1件)

    • 周辺設定件数、Hardware (US)ロースターのメンバー構成(Beth Anglin / David Loo)

    確認していない範囲(断定しません):

    • cmn_rota_scheduleテーブルは当PDIに存在せず確認できませんでした

    • オンコールの実時間展開エンジン(誰が「今」当番かを解決する内部ロジック)

    • エスカレーションの発火経路(Incident → On-Call Notificationの全経路)

    • Notify Now / Who's on callウィジェットの内部

    • コミュニケーションチャネル(SMS/メール)連携

    • 各Business Rule / UI Policyの内部スクリプト

    • 本番でのカスタムローテーション、On-Call Schedulingプラグインのバージョン依存差

    これらは別記事で扱います。実環境では、既存のカスタマイズによって当番表の定義・フィールド・件数が変わります。

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

    あなたへのおすすめ