cronを業務で使用して学んだこと

# はじめに
この度、cronを初めて業務で使用する機会がありました！
途中、STG環境に接続できなくなってしまうトラブルも発生しましたが。。
ですが、そこでの学びも多かったため、アウトプットしたいと思い書きました！

※この記事ではcrontabの書き方については触れないです、他記事でご確認ください。

# cronとは
cronはUNIX系のOS(Mac, Linuxなど)に入っていて、指定した時間に指定したプログラムを動かすものです。所謂、定期実行です。cronが起動している限り実行してくれます。
crontabというコマンドおよびファイルで、cronの設定を行います。“cron table” の略。

## 学んだこと
cronを業務で使用した際に、学んだことを記載していきます。

## 1. /etc/crontabでcrontabファイルを一元管理

前提、今のプロジェクトでは私がcronを実装する前から既に定期実行が行われているプログラムがありました。
crontabファイルを`crontab -e`コマンドで設定する記事をよく見かけるのですが、このプロジェクトでは、`/etc/crontab`で一元管理していました。
なぜ、`/etc/crontab`で管理しているのか、実装を行った業務委託の方に背景を伺いました。

> crontab -eだとユーザーごとに設定ファイルが作成されるため、定期実行が複数あった時に、この定期実行の設定はどのユーザーで管理してたっけ？　という管理コストが増えてしまう。
また、システムを移行する時にetcを圧縮して持っていくことが多く、ユーザー別に作成してしまうとetc配下に作成されないため抜け漏れてしまうことがある。

上記の理由で、/etc/crontabで管理するようになったそうです。
`/etc/crontab`と`crontab -e`の違いを簡単にまとめると以下のようになります。
| 設定方法 | 主な用途 | 　置かれる場所 |
|:-:|:-:|:-:|
| /etc/crontab  | システム共通 | /etc/crontab |
| crontab -e  | ユーザー個別 | /var/spool/cron/ユーザー名（ディストリビューションによって違う可能性あり） |

これ以外にも毎時（/etc/cron.hourly）、毎日（/etc/cron.daily）などの書き方がありますが、いずれも管理コストがかかるため採用しなかったとのことです。
システムを移行することがないのであれば`crontab -e`でも良いとのこと。
個人的にも、`/etc/crontab`で管理した方が見るべき箇所が1つになるし、見落としも減ると思うので良いと思っています！

勿論、`/etc/crontab`で管理するのが正解とかではないです。
この定期実行は、ユーザー個別に管理したいのか、システム共通で管理したいのかシステム移行の可能性があるのかなど使用用途を把握した上で、管理コストが増えないような運用にしましょう！

## 2. ログの見方
cronのログが出力されるパスは`/var/log/cron`になります。
私が業務でよく行なっていた編集から保存、確認までの一連の流れは以下になります。

1. crontabファイルをviで編集し、保存
2. `sudo tail -f /var/log/cron`でログを監視
3. 書き方に問題がないことを確認したのち、短い間隔（10分置きなど）で設定してみて、その日時にプログラムが動くかどうかを検証する
4. 本番で実行する日時に設定し、その日時にプログラムが実行されることを確認

<br>

**`sudo tail -f /var/log/cron`でログを監視**
crond（デーモン）は毎分、設定に変更があるか確認を行なっています。

<font color="green">**成功**</font>
![CleanShot 2024-06-15 at 18.02.43@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3741330/21d82800-4160-1398-4f45-a4a155f53ac5.png)
変更後、少し待ってRELOADの文言だけ出力されたら正常に変更が反映されたことを意味します。
また、時間になったら実行したプログラムのログが出力されます。

:::note warn
この成功は、あくまでcrontabファイルの書き方に問題がないだけで、指定したプログラムが正常に動くかどうかは保証されていません。
そのため、そもそもプログラムが正常に動くかどうかはcronの外で確認した上で設定することをオススメします。
:::
<font color="red">**失敗**</font>
![CleanShot 2024-06-15 at 18.00.22@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3741330/3a4fc563-9815-6268-92d5-73704e186c20.png)
crontabファイルの書き方に問題がある場合、少し待ってRELOADの文言が出力された後に、エラー文言が出力されます。

<br>

**書き方に問題がないことを確認したのち、短い間隔（10分置きなど）で設定してみて、その日時にプログラムが動くかどうかを検証する**

こちらは、冒頭の私がやらかしてしまったエピソードなのですが

:::note alert
早くプログラムが動くことを確認したいあまり、重たいプログラムを数分置きで設定すると。当たり前ですが、プログラムが正常に動作した時、数分ごとに実行されてしまいサーバーに負荷がかかりすぎてしまう可能性があるので要注意です！
:::

実際に、数分置きで実行してしまったところ、STG環境が開けなくなってしまい、SSH接続しようとしても固まってしまう問題が発生してしまいました。。
概要をお話すると、定期実行がメモリを占領してしまい、メモリが枯渇、スワップに手を出していた状況です、少しでも書き込む処理があると固まってしまいました。。

これから得た教訓としては、10分間隔くらいで検証してみるのがいいかと思いました！
そのくらいの余裕があれば、続けて実行される前に定期実行をコメントアウトすることができると思います。

## 3. コストを意識する
こちらは後日談で、業務委託の方からご教示いただいたのですが
> cronは裏側で実行されるものだから、動く時のリソース、メモリ、CPUをどのくらい消費しているのか。時間がかかっているのか。それがコストになるからそれを意識できるようになると良いです。

たしかに、コストまでは意識できていなかったので、どのくらいリソースを消費しているのか、時間がかかっているのかを把握することはとても大事だなと感じました。
あまりにもリソースを消費すぎていたり、時間がかかりすぎていた場合、プログラムを改修する必要があることも検討できるなと感じました。


# cronがうまく動かない時に確認すること
前提として、実行したいプログラムはcronの外で正常に動作するとします。

## 相対パスではなく絶対パス
ファイルのパスが相対パスだとうまく読み込まれなかったりします。そのため絶対パスで記述しましょう！
また、実行コマンドもフルパスにしないと正しく読み込まれなかったりします。そのため`which`コマンドで出力されたフルパスを指定しましょう。

# 最後に
cronを初めて業務で使用して、やらかしてしまったりもしたのですが、その時のデバッグ方法だったり、どのように検証を進めていくべきなのか私の中で見えてきたこともあったので貴重な体験をしたなと感じてます！
当時サポートしていただいた開発チームのみなさんには感謝しかないです🙇‍♂️
分からないことがあったらすぐ相談できる今の環境に感謝しつつ、またcronを使用する機会が訪れたら、今回学んだ経験を活かし、コストを意識しながら実装したいと思います！

ここまで読んでいただきありがとうございました！