
ServiceNowのスケジュールジョブは本当に動いている? run_countとnext_actionで見分ける
検証環境:Zurich PDI / OOTB / 2026-08-10 確認
夜間バッチが動いていない気がする。そう相談されたとき、担当者はまず一覧画面を開きます。ところがジョブが並んでいるだけでは「定義されている」ことしか分かりません。実際に走っているかどうかは別の話です。ServiceNowのスケジュールジョブには、実行回数を数える run_count と、最後に触られた時刻を持つ sys_updated_on というフィールドがあります。この2つを next_action(次回実行時刻)と突き合わせると、「定義はあるが一度も走っていない」ジョブや「以前は動いていたが止まっている」ジョブを見分けられます。今回は実際に1本のジョブを手動実行し、実行キューがどう変化するかまで実機で追いました。一覧を眺めるだけの調査から、実際に手を動かして確かめる調査への一歩を、そのまま記事にしています。
まず結論:一覧に並んでいることは、動いている証拠にならない
今回のPDIで確認した要点は3つです。
実行の予約(sys_trigger)は805件ありましたが、そのうち102件は run_count が0でした。予約だけです。一度も実行された形跡がありません。
next_action(次回実行時刻)が過去のまま止まっているジョブが115件あり、その中には trigger_type が Repeat(周期実行)でありながら run_count が半年近く増えていないものが実在しました。
「動いているかどうか」を確かめる最も確実な方法は、1回動かしてみることです。安全と確認できたジョブを1本選び、Execute Now で手動実行したところ、実行キューのレコードそのものが新しいレコードに置き換わるという、想定していなかった挙動が見えました。
見た目では分かりません。一覧だけで「動いている」と判断すると、この置き換わりのような細部を見落とします。

このフォームの右上にある「Execute Now」というボタンが、今回の実機確認の起点です。押すとどうなるか。後半で実際の変化を追います。
公式ドキュメントで押さえておきたい基本
スケジュールジョブの仕組みは、Scheduled jobsとSystem Schedulerという2本の公式ドキュメントで説明されています。スケジュールジョブの作成手順や各項目の意味はSchedule a script executionにまとまっています。条件付き実行など特殊なケースについては、Special cases in job schedulesを参照してください。
実行キューを処理する側の仕組みは、ServiceNowコミュニティの解説記事が詳しく扱っていました。Understanding Scheduled Job Workersによれば、各ノードは既定でScheduler Workerを複数本持ちます。待たされると増えます。優先度の高いジョブが長く待つ場合、追加のワーカーが動き出す設計とのことでした。ノード構成の違いはUnderstanding Application Nodesが詳しいです。今回のPDIは単一ノードでの実測のため、複数ノードでの分散までは確認していません。
個々のレコードを開かずに全体状況を俯瞰したい場合は、Scheduled Jobsダッシュボードも用意されています。System EventsとJobsダッシュボードを開くには専用のロールが必要です。本記事では、権限を持たない担当者でも開ける標準の一覧画面とフォームだけで、run_countとsys_updated_onから「本当に動いているか」を確かめる方法を扱います。
定義とキューの件数を先に数える
ServiceNowのスケジュールジョブは、「いつ・何を動かすか」を持つ定義(sysauto とそのサブクラス)と、「次にいつ動くか」を持つ実行キュー(sys_trigger)の2層構造です。この構造そのものは前回までの記事で詳しく確認しているため、ここでは件数だけ押さえます。

定義側(sysauto)は465件、うちアクティブが393件でした。スクリプトを実行する sysauto_script は386件、アクティブが339件です。実行キュー側の sys_trigger は805件で、ほぼ全件が state=Ready(次を待っている状態)でした。ここまでは「定義されている数」の話です。ここから先は「本当に動いているか」を見ていきます。
run_countが0のジョブは、一度も走っていない疑いがある
sys_trigger には run_count という整数フィールドがあります。そのトリガーが実際に何回実行されたかを数えるカウンタです。state=Ready で、起動時実行(Run at System Startup)を除いたうえで run_count=0 のレコードを数えると、102件ありました。

このリストには Disabled(無効)だけでなく、Interval や Repeat(本来は繰り返し実行されるはずの種別)も混ざっていました。定義済みで、次回実行時刻も入っていて、一覧上は他のジョブと同じ顔をしているのに、実行された記録がまったく無い。これが run_count の使いどころです。next_action だけを見ていると、この違いには気づけません。
起動時実行を除いて数えた理由
trigger_type が Run at System Startup(起動時実行)のジョブは、次に起動したときにしか動きません。インスタンスを再起動していない期間が長ければ、run_count が0のままでも仕様どおりです。この種別を含めたまま「run_countが0の件数」を数えると、正常なジョブまで疑いの対象に紛れ込みます。今回の102件は、この種別をあらかじめ除いた数字です。棚卸しをする際は、まず trigger_type を確認してから run_count を見る順番をおすすめします。種別を見ずに件数だけを追うと、母数の解釈を毎回誤ることになります。
next_actionが同じ分に何件も並んでいたら
次回実行が過去のまま止まっているレコードは、state=Ready・起動時実行を除いて115件でした。次回実行が古い順に並べると、興味深い並びが見えます。

上位には2013年という古い日付のレコードが2件ありましたが、これは Disabled(無効化済み)でした。無効化されたジョブが古い日付のまま残っているのは自然です。気になるのはその下に続く一群で、2026年2月2日の同じ時間帯に更新日時が集中していました。少なくとも20件のトリガーが、この1〜2秒の範囲に sys_updated_on を持っていたことを目視で確認しています。無関係な複数のジョブの更新時刻がここまで揃うのは、個々のジョブが別々に壊れたというより、インスタンス側の何らかの一括処理(クローンやリフレッシュなど)でトリガーがまとめて触られた痕跡だと考えられます。原因そのものは特定できていません。
半年動いていないRepeat型ジョブの実例
この一群の中に、trigger_type が Repeat の2件(Clean Remote Table Temp Files と Clean Temp Files)がありました。どちらも run_count は805件まで積み上がっていて、以前は確かに周期実行されていたことが分かります。ところがそこから半年近く、next_action も sys_updated_on も一切動いていません。Disabled であれば止まっていて当然ですが、この2件は種別としては今も「繰り返し実行」のままです。件数だけを見る調査では見逃しやすい実例だと感じました。
一方で、実行キュー全体が止まっているわけではありません。run_count が400万回を超えるジョブ(Process auto resolution events など)もあり、next_action はサーバの現在時刻から数秒先という値でした。このPDIのスケジューラそのものは、確認した時点で正常に動いていたことになります。止まっているのは一部のジョブだけでした。
この対比が今回の調査の出発点です。同じ一覧の中に、1秒先に次回実行が控えているジョブと、半年前から時計が止まったままのジョブが同居しています。次回実行時刻という1つの列だけを眺めていると、両者の違いに気づけません。run_countとsys_updated_onという、いつ動いたかを直接示す2つの値を並べて初めて、この差が見えてきます。
実際に1本、手動で動かしてみる
ここまでは画面を読む調査でした。ここからは、実際にジョブを1本動かして、実行キューがどう変化するかを見届けます。
どのジョブを選んだか
手動実行するジョブは、レコードを大量に作らない・消さない、メールを送らない、外部と通信しないものに限定しました。周期実行(Periodically)で active=true のジョブを一覧で眺め、名前とスクリプトの両方を見て候補を絞り込んでいます。
候補のうち、外したものにも理由があります。LDAP Connection Test は名前のとおり外部への接続確認が入っているため見送りました。Purge empty rollback contexts はレコードを削除する処理が入っているため対象から外しています。Notify new delegates は通知(メール)に関わる可能性がある名前だったため、中身を確認する前に候補から落としました。最終的に残ったのが「Populate navigator menu secondary caches」という3分周期のジョブです。
スクリプトを読んで安全を確認する
実行前に、このジョブの Run this script の中身を確認しました。
// Touch the global menu caches to make sure they are populated
SNC.NavigatorScriptableUtil.getNavigatorMenuAndFavorites();ナビゲータメニューのキャッシュを触れるだけの1行です。レコードの作成・更新・削除も、通信も発生しません。安全と判断し、このジョブを手動実行の対象にしました。実行前の run_count は50,467、次回実行は数分先という、ごく普通に動いている状態でした。
Execute Nowを押すと何が起きるか
フォーム右上の Execute Now を押すと、サーバ側では次のスクリプトが動きます(UI Actionの定義を確認したものです)。
current.update();
SncTriggerSynchronizer.executeNow(current);実行直後のフォーム画面
押した直後の画面は、見た目には元のフォームと変わりません。裏側で起きている変化は、フォームの見た目ではなく sys_trigger 側のレコードを読み直して初めて分かりました。

sys_trigger を読み直すと、想定と違う結果になりました。

run_count がそのまま加算されるのではなく、0にリセットされていました。さらに、実行前の sys_trigger の sys_id で検索し直すと、該当レコードが見つかりません。同じジョブなのに、実行キューのレコードそのものが新しいレコードに置き換わっていたのです。

新しいレコードは、その後も普通に周期実行を続けていきました。約3分後にrun_countが1、約6分後には2まで増え、next_actionも3分ずつ先へ進んでいます。stateは一貫してReadyのまま、error_countも0のままでした。この一連の変化そのものが「このジョブは今も生きている」という一番具体的な証拠になります。
もうひとつ気づいたのは、定義側(sysauto_script)の sys_updated_on も、実行と同じタイミングで更新されていたことです。UI Actionのスクリプトが current.update() を先に呼んでいるためで、定義の更新日時だけを見ても「最後に編集した日」なのか「最後に実行した日」なのかは区別できません。判断材料にするなら、定義側ではなく sys_trigger 側の run_count と sys_updated_on を見るほうが確実です。
動いていないと言われたときに、この順番で見る
ここまでの内容を、確認する順番として1枚にまとめました。

Active・state・next_action までは前回の記事でも扱った内容です。今回付け加えたのは、その先の run_count と sys_updated_on を見る段階と、判断がつかないときに実際に1回動かしてみるという最後の一手です。next_action が過去のままでも、run_count と sys_updated_on が直近で動いていれば心配は要りません。逆に、両方とも長期間動いていなければ、そこが最初に疑うべき候補になります。
実務でどう使えるか
障害調査の場面では、対象ジョブの名前が分かっていることがほとんどです。まず sys_trigger をジョブ名で検索し、run_count と sys_updated_on を見ます。直近数分から数時間で更新されていれば、たいてい生きています。数日から数週間動いていなければ、Active の確認とあわせて疑う対象です。
同じ考え方は、複数ジョブをまとめて棚卸しするときにも使えます。trigger_type=Repeat(周期実行のはず)のジョブだけを抽出し、sys_updated_on が古い順に並べれば、「種別上は動くはずなのに動いていない」候補を効率よく絞り込めます。今回の調査で見つけた24件(Repeat型のうち30日以上 sys_updated_on が動いていないもの)は、この絞り込み方で見つけたものです。件数だけを追うよりも、絞り込んだ候補を1件ずつ手動実行して確かめるほうが、結論に早くたどり着けます。
判断に迷ったときの最終手段はシンプルです。安全性をスクリプトで確認したうえで Execute Now を押し、数分待ってから run_count が増えているかを見る。それだけで「動くはずなのに動いていない」という疑いに、実測の答えを出せます。
毎回同じ手順を繰り返すのは手間なので、定期的な棚卸しには一覧の絞り込み条件を保存しておくと便利です。trigger_type=Repeat かつ sys_updated_on が一定期間より前、という条件だけでも「本来なら動いているはずなのに、しばらく動いていない」候補を機械的に洗い出せます。月に1回この一覧を開いて件数の変化を見るだけでも、障害が相談として上がってくる前に気づける場面は増えるはずです。
実機で気づいたこと
一番驚いたのは、Execute Now を押すと run_count が加算ではなくリセットされ、sys_trigger のレコードそのものが差し替わる挙動でした。ドキュメントにはここまで細かい記載が見当たらず、実際に前後のsys_idを突き合わせて初めて気づきました。数字が大きいから安心、ではありません。手動実行のたびに振り出しへ戻る仕組みを見落とします。
run_count=0のジョブを一覧で数えた直後、Execute Now を押した対象ジョブ自身が、一瞬だけこの「一度も走っていない」集合に含まれていました。新しく作られたレコードは、次に実行されるまでの数分間、当然ながら run_count=0 だからです。同じ0でも意味が違います。「壊れている0」なのか「生まれたばかりの0」なのかは、sys_updated_on の新しさで見分けるしかないと実感しました。
next_actionが同じ分に何十件も並ぶ光景は、個々のジョブ障害を疑う前に、まずインスタンス全体で何か起きていないかを確認したほうがよいという注意喚起に見えました。まず横を見る。同じ時刻を持つレコードが他に無いかを先に確認する癖をつけると、無駄な調査を減らせそうです。
次に読むなら
定義(sysauto)と実行キュー(sys_trigger)の2層構造そのものを詳しく知りたい場合は「定期実行(sysauto_script):定義と実行キューの2層」を読んでください。テーブルの継承関係とフィールド数を実機で追っています。次回実行が過去のままのジョブを一覧から探す基本の手順は「スケジュールジョブが動かないときの調べ方:sys_triggerの読み方」にまとめました。State別のグループ化やNext actionの並べ替えを、画面操作だけで行う方法です。今回の記事は、その先にある「run_countと更新時刻で本当に動いているかを見分け、実際に1本動かして確かめる」という一歩に進んだ内容です。3本を通して読むと、定義を読む・一覧で絞り込む・実際に動かして確かめるという3段階が一通りそろいます。
用語
sysauto(Scheduled Job):スケジュールジョブの定義を持つ基底テーブル
sysauto_script:sysautoの子テーブルで、スクリプトを実行する種類の定義
sys_trigger(Schedule Item):実行キュー。次回実行時刻と実行状態を持つ
next_action:sys_triggerが次に処理される予定の日時
run_count:そのsys_triggerレコードが実際に実行された回数
sys_updated_on:レコードが最後に更新された日時(標準の監査項目)
trigger_type:sys_triggerの予約種別。Repeat・Interval・Disabled・Run at System Startupなど
Execute Now:定義フォームから手動でジョブを即時実行するボタン(UI Action)
自分の環境で確認するときのURL
先頭に自分のインスタンスを付けると、同じ画面が開けます。
run_countが0の一覧 : sys_trigger_list.do?sysparm_query=run_count%3D0%5Estate%3D0%5Etrigger_type!%3D9%5EORDERBYnext_action
next_actionの古い順 : sys_trigger_list.do?sysparm_query=state%3D0%5Etrigger_type!%3D9%5EORDERBYnext_action
定義一覧(スクリプト) : sysauto_script_list.do?sysparm_query=active=true^ORDERBYname
特定ジョブのフォーム : sysauto_script.do?sys_id=<対象のsys_id>検証範囲とおことわり
確認した範囲:sysauto/sysauto_script/sys_trigger の件数、next_actionが過去のまま止まっているジョブの件数(起動時実行を除く)、run_count=0のジョブの件数とその一時的な増減の理由、Repeat型トリガーのうち直近30日更新が無いものの件数、Execute Now(UI Action)のスクリプト本体、手動実行前後のsys_trigger(sys_id・run_count・next_action・sys_updated_on・state)の変化を約6分間追跡しました。すべてPDI(Zurich / OOTB)の実測です。
確認していない範囲(断定しません):sys_updated_onが特定の時刻に集中していた根本原因、スケジューラの内部実行ロジックや複数ノードでの分散、run_countがリセットされる条件の網羅(Execute Now以外の操作で同様の挙動になるかは未検証)、Disabledトリガーと定義側の個別の対応関係、6分を超える長期間の追跡です。
sys_triggerは常時更新される動的なテーブルです。今回の記事を読み直すタイミングによって、件数は本記事の実測値から変わっている可能性があります。本番環境ではジョブの数や実行間隔がさらに異なります。