Fly.io の「Cron and Queues」のページに従って定期処理の設定をやってみた

### 前提

- [Fly.io](https://fly.io/)のページについては、2024年8月24日時点の構成で説明しています。
- 検証環境
    - MacBook Pro(Intel)
        - macOS Sonoma 14.5
- ローカル環境にFly.ioにデプロイ済みのアプリケーションがある。
    - デプロイ用のDockerfileとfly.tomlが作成済みの状態。

---

[Fly.io](https://fly.io/)のページにアクセスし、画面上部メニューのから「[Docs](https://fly.io/docs/)」をクリックします。

![スクリーンショット 2024-08-07 9.16.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/36ed6739-5556-5ef5-5623-1df4fba37262.png)

---

検索フォームから「Cron」と入力します。

![スクリーンショット 2024-08-07 9.17.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/d6e8072f-567d-2a30-f6dc-f6ac6bf3b7da.png)

「Cron and Queues」がヒットするのでクリックします。

![スクリーンショット 2024-08-24 9.09.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/d0d22115-b1d7-acaf-2d2d-763db099c3ce.png)

「[Cron and Queues](https://fly.io/docs/laravel/the-basics/cron-and-queues/)」のページに従って作業を進めていきます。
※こちらの記事ではLaravelにおける説明となっていますが、一般的な定期処理の場合でも動作します。

---

以下の説明が記載されています。

![スクリーンショット 2024-08-24 9.16.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/3f6f74f4-69b1-660a-ebf3-f908a0bd7634.png)

Laravelで定期処理やキューの仕組みを利用する場合は「[process](https://fly.io/docs/reference/configuration/#the-processes-section)」の設定を行うことで、アプリケーションのグループを分割して対応可能とのこと。
このあたりについては、以前書いた「[Fly.io の「Crontab with Supercronic」のページに従って定期処理の設定をやってみた](https://qiita.com/akase244/items/fdb3368b5f0aa0b77d26)」の記事でも説明しているので、ご参照ください。

---

まず、定期処理用の設定ファイルを作成します。
以下の説明のとおり、作成した設定ファイルを「/etc/cron.d」配下に配置するように設定していきます。

![スクリーンショット 2024-08-24 9.24.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23093/a2ec1a07-bd26-b228-808e-5bfaf8a014e1.png)

定期処理用の設定ファイルを準備する際の注意点として、「crontab -e」で定期処理を設定する場合の書式と「cron -f」で読み込む場合の設定ファイルの書式は少々異なるという点です。

以下は「Debian GNU/Linux 12 (bookworm)」で「cron 3.0pl1-162」をインストールした場合の「/etc/crontab」の内容ですが、「crontab -e」とは違い、6番目の項目として「user-name」の指定が必要となるので、こちらをお忘れなく。

```
# cat /etc/crontab 
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17 *	* * *	root	cd / && run-parts --report /etc/cron.hourly
25 6	* * *	root	test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6	* * 7	root	test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
52 6	1 * *	root	test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }
#
```

ということで「/etc/cron.d」配下に配置するための「crontab」という設定ファイルを準備します。
[Supercronic](https://qiita.com/akase244/items/fdb3368b5f0aa0b77d26)で定期処理の設定を行った場合はFly.ioのLive Logs画面で実行時間を確認することができましたが「cron -f」で設定する場合は、cronが実行されたことを確認する方法がないため、ここでは5分に1回「/var/log/cron.log」に実行時間を出力するようにしておきます。

```
% cat crontab
*/5 * * * * root echo "cron run at: $(date)" >> /var/log/cron.log
```

---

- Fly.ioのデプロイで利用しているDockerfileに以下の記述を追加します。
    - cronをインストールします。
    - 事前に作成しておいた「crontab」をコピーします。

```
RUN apt-get update -qq && \
    apt-get install -y cron

COPY crontab /etc/cron.d/
RUN chmod 0644 /etc/cron.d/crontab
```

---

- Fly.ioのデプロイで利用しているfly.tomlに以下の記述を追加します。
    - 「processes」を「cron」と「web」で分割します。Laravelの場合は「`app = ""` is needed」という説明がありましたが、この環境ではNode.jsのアプリケーションを動作させるために「`npm run start`」を指定しています。

```
[processes]
  cron = 'cron -f'
  web = 'npm run start'

[http_service]
  ・
  ・
  processes = ['web']

[[vm]]
  size = 'shared-cpu-1x'
  processes = ['cron', 'web']
```

---

準備が整いましたのでデプロイを実行します。

```
% fly deploy
```

---

`fly machine list` コマンドで作成済みの仮想マシンの一覧を表示します。
対象となるIDの値（今回の場合は「PROCESS GROUP」が「cron」のID）を控えておきます。

```
% fly machine list
2 machines have been retrieved from app [アプリケーション名].
View them in the UI here (​https://fly.io/apps/[アプリケーション名]/machines/)

[アプリケーション名]
ID            	NAME                STATE  	CHECKS	REGION	ROLE	IMAGE                                                    IP ADDRESS                      VOLUME	CREATED       LAST UPDATED         PROCESS GROUP SIZE                
XXXXXXXXXXXXXX	XXXX-XXXXXXXX-9999	started	      	nrt   	    	[アプリケーション名]:deployment-XXXXXXXXXXXXXXXXXXXXXXXXXX	XXXX:9:XXXX:XXX:XXX:XXXX:XXXX:9	2024-08-10T11:34:56Z 2024-08-25T01:59:35Z cron          shared-cpu-1x:256MB	
ZZZZZZZZZZZZZZ	ZZZZ-ZZZZZZZZ-8888  stopped	      	nrt   	    	[アプリケーション名]:deployment-ZZZZZZZZZZZZZZZZZZZZZZZZZZ	ZZZZ:8:ZZZZ:ZZZ:ZZZ:ZZZZ:ZZZZ:8	2024-08-10T11:35:15Z 2024-08-25T01:59:28Z web           shared-cpu-1x:256MB
```

---

`fly console` コマンドの引数 --machine に先ほど控えておいたIDを指定して、仮想マシンにログインします。

```
% fly console --machine XXXXXXXXXXXXXX
Connecting to XXXX:9:XXXX:XXX:XXX:XXXX:XXXX:9... complete
root@XXXXXXXXXXXXXX:/app#
```

---

`/var/log/cron.log` を `tail` コマンドでしばらく監視してみると、5分毎に定期処理が実行されていることが確認できました。

```
root@XXXXXXXXXXXXXX:/app# tail -f /var/log/cron.log 
cron run at: Sun Aug 25 02:00:01 UTC 2024
cron run at: Sun Aug 25 02:05:01 UTC 2024
cron run at: Sun Aug 25 02:10:02 UTC 2024
cron run at: Sun Aug 25 02:15:01 UTC 2024
```

---

- 参考URL
    - [Cron jobs/scheduler on Fly.io?](https://community.fly.io/t/cron-jobs-scheduler-on-fly-io/7791/1)
    - [Running Laravel's Scheduled Tasks via CRON on Fly.io](https://www.youtube.com/watch?v=TUZLsT5Sw8U)