Concrete CMS タスク設定方法: systemd timer 版 (V9 以降)


Concrete CMS v9 よりバッチ処理をバックグラウンドで行うための新しい「タスク」機能

サーバーの設定を Cron じゃなくて、 Systemd timer を使って実装してみました。systemd timer を使う場合、root 権限があるサーバー (専用、VPS、クラウド) が必要な場合が多いです。

crond は日時でしか指定できないのですが、systemd は「前のプロセスが終わったら○秒後に実行」という設定も可能。つまりプロセスの二重起動の心配が無い！

またタイマーに依存関係も持たせることができてしまいます。

その分、設定も複雑になってしまいます。

今回はその手順を Concrete CMS に特化してお教えします。

Cron を使ってタスクを設定する場合はこちら

**Concrete CMS タスク設定方法: Cron版  (V9 以降)**
https://qiita.com/katzueno/items/ad7598565f4909c697ae


# 初期設定

## 1. Concrete CMS 管理画面での設定

- 管理画面 -> システムと設定 -> 自動化 -> 自動化設定 ページに訪問
	- [Concrete URL]/index.php/dashboard/system/automation/settings
- `キューを確認する` を `手動` に変更
- (オプション) `ログ` を保存したければ、ログ保存先をサーバー上に作成、そして「ログ」の設定を`無効` から `ファイル` に変更し、`Log Directory` に、サーバーパスを入力 (**root権限のあるサーバー向け**)
	- 例: `/var/log/ccm-task` で設定する場合
		- `sudo mkdir /var/log/ccm-task`
		- `sudo chown 【nginx:nginx, apache:apache, もしくはSSHユーザー】 /var/log/ccm-task`
		- `sudo chmod 755 /var/log/ccm-task`
		- ログは肥大化するので、logrotate を有効にしよう (STEP 7 参照　)
- `スケジューラー` を `有効` に変更
- 保存


## 2. タスクスケジューラーを設定


`ccm-task-scheduler` というサービスを登録

```
sudo vi /etc/systemd/system/ccm-task-scheduler.service
```

内容はこちら。

- `User`, `Group` には、現在の Concrete CMS 自信が利用しているユーザー・グループを入れてください。サンプルは nginx:nginx で Concrete CMS を動かしている際のサンプルです。
- `ExecStart` には、Concrete CMS の CLI を実行するためサーバーのフルパスをいれて入れてください

```
[Unit]
Description=ccm-task-scheduler

[Service]
User=nginx
Group=nginx
Type=oneshot
ExecStart=/var/www/vhosts/example.com/concrete/bin/concrete concrete:scheduler:run
```

次に `ccm-task-scheduler` のタイマーを登録。

スケジューラーは

- サーバー起動時から1分待つ
- それからは1分ごとに起動

```
sudo vi /etc/systemd/system/ccm-task-scheduler.timer
```

内容はこちら。

```
[Unit]
Description=ccm-task-scheduler

[Timer]
OnBootSec=1min
OnUnitActiveSec=1min
Persistent=true

[Install]
WantedBy=timers.target
```


## 3. コンシューマーを設定

`ccm-task-consumer` というサービスを登録

```
sudo vi /etc/systemd/system/ccm-task-consumer.service
```

- `User`, `Group` には、現在の Concrete CMS 自信が利用しているユーザー・グループを入れてください。サンプルは nginx:nginx で Concrete CMS を動かしている際のサンプルです。
- `ExecStart` には、Concrete CMS の CLI を実行するためサーバーのフルパスをいれて入れてください
- メモリリークやタイムアウトの心配もあるので、10分で一旦停止するようにします。もしもタスクの中に1実行時間が数分にもわたるようなタスクがあれば、実行時間を調整するべきかと思います。

```
[Unit]
Description=ccm-task-consumer

[Service]
User=nginx
Group=nginx
Type=simple
ExecStart=/var/www/vhosts/example.com/concrete/bin/concrete messenger:consume async --time-limit=600
```

次に `ccm-consumer-scheduler` のタイマーを登録。

```
sudo vi /etc/systemd/system/ccm-task-consumer.timer
```

内容は以下の通り

- サーバー起動時から1分待つ
- コンシューマー自身が10分で停止するはず
- 停止したら1秒後に再起動


```
[Unit]
Description=ccm-task-consumer

[Timer]
OnBootSec=1min
OnUnitActiveSec=1s
Persistent=true

[Install]
WantedBy=timers.target
```


## 4. Config を反映させる

変更を加えたときは実施しましょう。

```
sudo systemctl daemon-reload
```

## 5. サービスをスタートアップ登録 & 有効化

サーバー再起動時にタイマーが起動するようにします。

```
sudo systemctl enable ccm-task-scheduler.service
sudo systemctl enable ccm-task-consumer.service
sudo systemctl enable ccm-task-scheduler.timer
sudo systemctl enable ccm-task-consumer.timer
```

タイマーのサーバー再起動時に起動するよう設定されているか確認

```
sudo systemctl is-enabled ccm-task-scheduler.timer
sudo systemctl is-enabled ccm-task-consumer.timer
```

## 6. サービスを起動

```
sudo systemctl start ccm-task-scheduler.service
sudo systemctl start ccm-task-consumer.service
sudo systemctl start ccm-task-scheduler.timer
sudo systemctl start ccm-task-consumer.timer
```

## 7. (オプション) logrotate を設定しよう

サーバー内にログファイルを保存するように設定したのなら、ログファイルが肥大化しないように、logrotate を設定しよう。

「1. Concrete CMS 管理画面での設定」のサンプルで `/var/log/ccm-tasks/` ディレクトリ配下に保存するように設定したと仮定します。

```
sudo vi /etc/logrotate.d/ccm-task
```

週間で log rotate & 圧縮して、半年間保持する設定です。

```
/var/log/ccm-task/*log {
        weekly
        rotate 26
        missingok
        notifempty
        compress
        sharedscripts
}
```

# 8 systemd timer 動作確認・設定

動作確認方法

## 8-1. 各サービス・タイマーのステータス

```
sudo systemctl status ccm-task-scheduler.service
sudo systemctl status ccm-task-consumer.service
sudo systemctl status ccm-task-scheduler.timer
sudo systemctl status ccm-task-consumer.timer
```

## 8-2. タイマー実行確認

タイマーの前回実行時間、次回実行時間、経過時間などを確認できます。

```
sudo systemctl list-timers
```

## 8-3. ログ確認

```
sudo journalctl -e
```

## 8-4. 停止方法

```
sudo systemctl stop ccm-task-scheduler.timer
sudo systemctl stop ccm-task-consumer.timer
sudo systemctl disable ccm-task-scheduler.timer
sudo systemctl disable ccm-task-consumer.timer
```

# 9 Concrete CMS 側タスクの設定方法

実際にタスクをスケジュール設定し、タスクが正常に動くか確認しましょう。

## 9-1 タスクをスケジュールしてみる

sitemap.xml や索引インデックスのタスクを管理画面から設定します。

- 管理画面 -> システムと設定 -> 自動化 -> タスク に訪問
	- `コンクリのトップ/index.php/dashboard/system/automation/tasks`
- スケジュール設定したいタスクを選ぶ
- スクロールダウンし `タスク実行` メニューが表示されます
- `すぐに` か `定期的なタスクをスケジュール` の選択項目の後者を選択します。
- `Cron expression` という Cron 形式で実行時間を指定します。

## 9-2 Cron expression とは

曜日・月・日・時間・分を指定するための式みたいなものです。
アスタリスクをいれると、毎分・毎時間・毎日などと複数回設定できる様になります。

```
分・時・日・月・曜日
```

### 9-2-1 例: 毎朝8時に実行

```
0  8  *  *  *  *
```

### 9-2-2 例: 1/1 0:00 に実行

```
0  0  1  1  *  *
```

### 9-2-3 例: 毎週月曜日 0:00 に実行

```
0  0  *  *  *  1
```

これで、タスクによる Cron 設定を行うことができます。

# 10. Enviroment を使って Concrete CMS の config 環境を変える方法

Concrete CMS には、変数を設定することで、同じコードベースでも、本番・検証・開発の設定(Config)ファイルを用意し、変数に応じて読み込む config を変えることができる機能がついています。

参考: [Concrete CMS で環境ごとに別の設定ファイルを読み込む方法](https://qiita.com/katzueno/items/43258716424aac82468f)

## 10-1 タスクスケジューラーの設定例

ENV名 `production` で Concrete CMS のタスクを起動する例。`Environment="CONCRETE5_ENV=production"` を適宜、変数を変えてください。

```
[Unit]
Description=ccm-task-scheduler

[Service]
User=nginx
Group=nginx
Type=oneshot
Environment="CONCRETE5_ENV=production"
ExecStart=/var/www/vhosts/example.com/concrete/bin/concrete concrete:scheduler:run
```

## 10-2 コンシューマーを設定

ENV名 `production` で Concrete CMS のタスクを起動する例。`Environment="CONCRETE5_ENV=production"` を適宜、変数を変えてください。

```
[Unit]
Description=ccm-task-consumer

[Service]
User=nginx
Group=nginx
Type=simple
Environment="CONCRETE5_ENV=production"
ExecStart=/var/www/vhosts/example.com/concrete/bin/concrete messenger:consume async --time-limit=600
```


# 参考

https://man.archlinux.org/man/systemd.timer.5
https://gamingpc.one/dev/systemd-timer-cheat/
https://wiki.archlinux.jp/index.php/Systemd/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC
https://forums.concretecms.org/t/how-we-can-set-env-for-task-in-v9-like-we-used-to-do-in-v8/4888