この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。systemd-analyze、systemd.timer、systemd.timeの公式マニュアルを確認し、次の起動時刻を読み取り専用で調べるサンプルを作成しました。対象Ubuntuでの実行確認はまだ行っていません。
検証ステータス:📘 systemd公式マニュアル確認済み・Ubuntu実機未確認
Ubuntuで*.timerを設定したのに、想定した時刻にサービスが動かないことがあります。よくある勘違いは、カレンダー式が正しいことと、実際のタイマーが有効になっていることを同じと考える点です。
systemd-analyze calendarを使うと、タイマーを有効化せずに、OnCalendar=と同じ形式の式を解釈し、次の実行予定日時を一覧できます。さらにPersistent、AccuracySec、タイムゾーンを分けて確認すると、見落としを減らせます。
最小実験:2時間ごとの時刻を計算してみる
例えば、日本時間で00:05、02:05、04:05、…、22:05に実行したい場合、カレンダー式は次のように記述します。
[Timer] OnCalendar=*-*-* 00,02,04,06,08,10,12,14,16,18,20,22:05:00 Asia/Tokyo Persistent=false
これは設定例です。まだサービスやタイマーは有効にしません。
Ubuntuで次のコマンドを実行してください。
systemd-analyze calendar --iterations=8 \ '*-*-* 00,02,04,06,08,10,12,14,16,18,20,22:05:00 Asia/Tokyo'
この操作ではsudoは不要で、WordPressなどの本番サービスも起動しません。日時の構文を解析し、次の8回の発火予定を計算するだけです。出力される年月日や曜日は、実行する時点によって変わります。
Original form: ... Asia/Tokyo Normalized form: ... Next elapse: (次の偶数時05分に相当する日時) Iter. #2: (さらに2時間後) ...
※上記は表示項目の例示であり、実機ログの転記ではありません。
1か所変えて観察する
確認したいのは、毎時00分と2時間に1回の違いです。
# 毎時00分 systemd-analyze calendar --iterations=4 \ '*-*-* *:00:00 Asia/Tokyo' # 偶数時05分 systemd-analyze calendar --iterations=4 \ '*-*-* 00,02,04,06,08,10,12,14,16,18,20,22:05:00 Asia/Tokyo'
両者の出力でNext elapseとIter. #2の間隔を比較します。前者は約1時間間隔、後者は約2時間間隔で計算されるはずです。これで、意図したスケジュールが式に落ちているかを、実サービスを動かさず確認できます。
Daily-Code-Samplesのスクリプトには、この確認をひとまとめにしたpreview-calendar.shを保存しました。任意のカレンダー式を引数として渡せます。
bash preview-calendar.sh bash preview-calendar.sh '*-*-* 08:30:00 Asia/Tokyo'
「予定時刻が正しい」と「実際に動く」の違い
| 調べたいこと | 確認するもの | 分かること |
|---|---|---|
| カレンダー式の文法 | systemd-analyze calendar | 次回の発火予定 |
| タイマーが登録・有効化済みか | systemctl list-timers --all | 現在管理されているタイマー |
| Unitの定義 | systemctl cat 名前.timer | OnCalendarやPersistent等の設定 |
| 直近のサービス実行結果 | systemctl status 名前.service | 現在のプロセス状態と直近の実行 |
| エラーの詳細 | journalctl -u 名前.service | サービスのログ |
カレンダー式が正しくても、timerがinactiveやdisabledなら、通常は予定どおり自動実行されません。またタイマーが動いても、サービス本体が失敗すれば処理は完了しません。
次の操作は既存設定を読み取るだけです。調査対象は自分が管理する名前に置き換えてください。
systemctl list-timers --all --no-pager systemctl cat example.timer systemctl show example.timer \ -p ActiveState -p Unit -p NextElapseUSecRealtime -p LastTriggerUSec journalctl -u example.service --no-pager -n 30
見つからないUnitを指定してもよいわけではありません。実際のtimer名を確認してから読み替えます。閲覧権限によっては一部のJournalを読めない場合があります。
Persistentをtrueにすると、何が起こる?
Persistent=trueは、OnCalendarに基づくタイマーが停止・未稼働だった間に発火予定を逃した場合、再起動時などに追いつく動作を可能にする設定です。
| 設定 | 主な意味 | 実務上の注意 |
|---|---|---|
Persistent=false | 停止中の発火を無条件に取り戻す設定にしない | 公開・課金処理などの予期しない遅延実行を防ぎやすい |
Persistent=true | 停止中に逃したカレンダー実行の追いつきを可能にする | 復旧直後に想定外の実行が起きないか確認 |
AccuracySec | 発火時刻の精度ウィンドウ | 予定時刻ぴったりではない場合がある |
誤解しやすいのは、Persistent=trueにすれば「逃した分を1件ずつ全部再実行する」と思ってしまうことです。これは保証されません。タイマーはサービスを起動する仕組みであり、処理対象キューの未処理件数や公開の重複まで管理しません。
例えば2時間ごとにブログを1本投稿する場合、サーバーが12時間停止していたからといって、過去の6回分を一括で投稿するのは危険です。タイマーには遅延発火を制限する設定を使い、アプリ側で「当日分だけ」「この2時間枠では最大1本」を検査する必要があります。
タイムゾーンが違う場合
OnCalendar=*-*-* 08:30:00とだけ書いた場合、ホストのタイムゾーン設定が影響します。クラウドサーバーがUTCの場合、日本で見た08:30と一致しません。
timedatectl date '+%Y-%m-%d %H:%M:%S %Z' systemd-analyze calendar '*-*-* 08:30:00 Asia/Tokyo'
カレンダー式にAsia/Tokyoと書くことで、時刻の基準を明示できます。ただし、サーバーの時計の同期状態そのものが不正確なら、カレンダーの解釈が正しくても実際の動作がずれます。
AccuracySecとサービス処理時間
OnCalendarに時刻を指定しても、AccuracySecの精度幅やサービスの起動待ちなどで、指定した秒と完全一致する保証はありません。一般的なLinuxの性能問題だけではなく、Unitの設定も確認してください。
また、同じサービスが起動中かどうか、サービス実行にどれだけ時間がかかるかも運用の重要な条件です。タイマー側の予定が2時間間隔でも、アプリが無制限に再試行する設計なら2時間に1回の処理上限にはなりません。
時刻制御=timer、対象の妥当性=アプリ、実行結果=ログやDBと責任を分けることで原因を追いやすくなります。
実務で確認したい5項目
OnCalendarをsystemd-analyze calendarで評価できるか。タイムゾーンを明示しているか。
timer自体が有効で、次の予定時刻を持つか。
PersistentとAccuracySecが意図した振る舞いか。発火後のserviceの終了状態・ログまで照合したか。
この順に確認すれば、「時刻指定が間違っている」「タイマーが無効」「サービスが異常終了」「実際の業務処理は0件だった」という異なる原因を分けられます。
