Linux ジョブスケジューリング


# `cron`

[デーモン](https://qiita.com/AsahinaKei/items/e354a3814639aeac4138#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9--%E3%83%87%E3%83%BC%E3%83%A2%E3%83%B3) の **`crond`** として稼働しているジョブスケジューラ。

`crond` は毎分ごとに、`crontab` ファイルの設定に従って実行すべきジョブがあるかを判定、実行する（`crontab` で設定できる最小単位は 1 分）。

`cron` を利用することで、指定した時間や間隔でコマンドやスクリプトをスケジューリングすることができる。

## `crontab` ファイル
cron table

`crontab` ファイルには、`cron` ジョブが記載される。

- **ユーザごと**
    - `/var/spool/cron/ユーザ名`
    - `/var/spool/cron/crontabs/ユーザ名`
    - エディタで **直接編集しない**（`$ crontab -e` を使用する）
- **システム全体**
    - `/etc/crontab`
    - `/etc/cron.d/`（ディレクトリ）
    - エディタで **直接編集する**

`crontab` ファイルの書式は以下のように **小さい単位から大きい単位** の順に記述する。

```:ユーザごとの crontab
分 時 日 月 曜日 コマンド
```

```:システム全体の crontab
分 時 日 月 曜日 ユーザ名 コマンド
```

| 設定項目 | 指定可能な範囲 |
|:-|:-|
| 分 | `0` ~ `59` |
| 時 | `0` ~ `23` |
| 日 | `1` ~ `31` |
| 月 | `1` ~ `12` |
| 曜日 | `0` ~ `7` （`0` または `7`：日曜日） |


| 特殊文字 | 意味 |
|:-:|:-|
| `*` | 全ての値<br> `* * * * *`：毎分実行 |
| `,` | 複数指定<br>`0,30 * * * *`：毎時 0 分と 30 分 |
| `-` | 範囲指定<br>`10-15 * * * *`：毎時 10 分 ～ 15 分の間（10, 11, 12, 13, 14, 15分）<br>`0 12 1-5 * *`：毎月 1 日 ~ 5 日 |
| `/` | 間隔指定<br>`*/5 * * * *`：5 分ごと |

```:例（毎日午前3時にスクリプトを実行）
0 3 * * * myscript.sh
```

```:例（毎分スクリプトを実行）
* * * * * myscript.sh
```

## `/etc/cron.allow` / `/etc/cron.deny`

ユーザが `cron` ジョブを実行できるかどうかを制御する設定ファイル。

- `/etc/cron.allow`
    - `cron` ジョブを実行できるユーザを指定する
- `/etc/cron.deny`
    - **`/etc/cron.allow` がない場合にのみ使用される**
    - `cron` ジョブの実行を禁止するユーザを指定する

## `$ crontab`

`cron` ジョブ（スケジュールされたタスク）を管理するためのコマンド。

特にユーザごとの [`crontab`](#crontab-ファイル)（`/var/spool/cron/`）を編集するために利用される。

`$ crontab -e` コマンド実行すると、`crontab` ファイルが規定のエディタによって開かれるため、内容を編集することでジョブを設定することができる。

エディタは [環境変数](https://qiita.com/AsahinaKei/items/22d9fae93cabfbf137ee#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0) `$VISUAL` または `$EDITOR` に設定されたものが起動される（`nano`、`vim` など）。

```console:エディタを利用して crontab ファイルを編集する（edit）
$ crontab -e
```

各ユーザが `$ crontab -e` で編集する内容は、内部的には `/var/spool/cron/crontabs/ユーザ名` に保存される（システムによっては `/var/spool/cron/ユーザ名` になることもある）。

ファイルの名前にユーザ名が使用されることからもわかるように、`crontab` ファイルへの編集は各ユーザごとに独立しており、他のユーザのジョブには影響しない。

```console:現在の crontab を表示する（list）
$ crontab -l
```

```console:crontab ファイルを削除する
$ crontb -r
```

# `anacron`

`cron` 同様に設定ファイルでスケジュールされたタスクを実行するジョブスケジューラ。

**厳密には `cron` のようにバックグランドで常駐するタイプのデーモンではなく、呼び出された時に一度だけジョブのチェックを行い、必要なジョブを実行するプログラム**。

`crond` デーモンもしくは `systemd-timer` によって起動される。

`cron` は予定された時刻にシステムが起動していない場合、ジョブの実行をスキップするのに対して、`anacron` は実行できなかったジョブをスキップせず、次回起動時にまとめて実行する。

`/etc/anacrontab` で設定を行う。

## 設定ファイル

`anacron` は `/etc/anacrontab` の設定に従い、以下のディレクトリに配置されたコマンドを実行する。 

| ディレクトリ | 説明 |
|:-|:-|
| `/etc/cron.hourly/` | 1 時間ごとに実行するスクリプトを配置 |
| `/etc/cron.daily/` | 1 日ごとに実行するスクリプトを配置 |
| `/etc/cron.weekly/` | 1 週間ごとに実行するスクリプトを配置 |
| `/etc/cron.monthly/` | 1 ヶ月ごとに実行するスクリプトを配置 |

# `atd`

指定したコマンドを指定した時刻に 1 回限りで実行するデーモン。


## `/etc/at.allow` / `/etc/at.deny`

ユーザが `at` ジョブを実行できるかどうかを制御する設定ファイル。

- `/etc/at.allow`
    - `at` ジョブを実行できるユーザを指定する
- `/etc/at.deny`
    - **`/etc/at.allow` がない場合にのみ、利用される**
    - `at` ジョブの実行を **禁止するユーザを指定する**

**どちらもない場合には、一般ユーザに許可されないt `root` ユーザのみが実行できる**。

## `$ at`

指定したコマンドを 1 回限りで実行する。

[`$ crontab`](#-crontab) が定期的なジョブ実行を行うの対して、`$ at` は 1 回だけ指定した時間で実行したい場合に利用される。

`$ at` コマンドで追加されたジョブは `atd` (`/usr/sbin/atd`) デーモンによって実行される。

`$ at` コマンドを実行すると、[標準入力](https://qiita.com/AsahinaKei/items/301b88e464c23aba231e#%E6%A8%99%E6%BA%96%E5%85%A5%E5%8A%9B--stdin) からジョブ（実行コマンド）を受け付けるモードに入る。

```console:指定した日時にコマンドを実行する
$ at 時間 日付
```

対話モードになったら、実行させたいコマンドを入力する。`Ctrl` + `D` キーで入力を終了する。

```console:スケジュールされたジョブを確認する
$ at -l
```

```console:ジョブの中身（スクリプト）を確認する
$ at -c ジョブID
```

```console:スケジュールされたジョブを削除する（delete / remove）
$ at -d ジョブID
$ at -r ジョブID
```

## `$ atq`

```console:スケジュールされたジョブを確認する
$ atq
```

## `$ atrm`

```console:スケジュールされたジョブを削除する
$ atrm ジョブID
```

# `$ batch`

システムがアイドル状態（負荷が少ない状態）の時にジョブを実行させる。

**時刻を指定することはできない**。

```console:ジョブを登録する
$ batch 
```

`$ batch` コマンドを実行すると、登録するジョブを入力するための対話が開始される。実行したいコマンドが入力し終えたら、`Ctrl` + `D` を同時押しで対話を終了することができる。

`$ batch` は [標準入力](https://qiita.com/AsahinaKei/items/301b88e464c23aba231e#%E6%A8%99%E6%BA%96%E5%85%A5%E5%8A%9B--stdin) からジョブを受け取るため、以下のようにすることでスクリプト実行をジョブとして登録することができる。

```console:スクリプト実行をジョブとして登録する
$ echo "bash ./myscript.sh" | batch
```

また `$ batch` は `$ at` と同様に `atd` デーモンによって管理され、以下のような `$ at` と共通の機能を持つ。

- [`$ atq`](#-atq) で登録済みジョブを確認できる
- [`$ atrm`](#-atrm) で登録済みジョブを削除できる
- [`/etc/at.deny`](#etcatallow--etcat) で実行を禁止するユーザを登録することができる


# タイマーユニット

[systemd](https://qiita.com/AsahinaKei/items/e354a3814639aeac4138#systemd) のタイマーユニット（`*.timer`）は、`cron` と同様に定期的なタスクを実行するための機能。

`cron` よりも柔軟で管理しやすいメリットがあるが、使い方が難しい。

ジョブを実行する `cron` とは異なり、ターマーユニットは `systemd` のサービス (`*.service`) をスケジュール実行する。

通常の `systemd` タイマー（`/etc/systemd/system/`）は `root` 権限で設定するが、一般ユーザでも `~/.config/systemd/user/` を使えばユーザ単位での `systemd` タイマーを設定できる。

`.timer` ユニットと `.service` ユニット から構成される。

- `.timer` ユニット
    - タイマーの設定
    - いつ、どのように実行するかを定義する
- `.service` ユニット
    - 実行する処理
    - 実際に実行するコマンドやスクリプトを定義する

`cron` では 1 つのファイル（`crontab`）でスケジュールとコマンドを設定するが、systemd では スケジュール（`.timer`）とコマンド（`.service`）を分けることで管理しやすくなっている。