venv環境でpythonスクリプトをcronで周期実行

cronにpythonのジョブを登録してvenv環境で周期実行するためには
#結論
使いたいvenv環境下のpythonを使えばよい。

```
$ crontab -e
* * * * * cd [絶対パス]; venv/bin/python foo.py
```

#具体例
一分に一回、日時をjsonline形式でファイルに書き出したい。

OS環境

```
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.14.6
BuildVersion:	18G87
```

ディレクトリを作り、venv仮想環境作り、今回使うパッケージjsonlinesをインストール。

```
$ mkdir [場所]
$ cd [場所]
$ python -V
Python 3.7.1
$ python -m venv venv
$ source venv/bin/activate
(venv) $ pip install jsonlines
```

pythonスクリプトを書く。処理された日時をjsonlineとして、out.jsonlに書き出す、というものです。確認のためprintも。

```python:dt2jsonl.py
import datetime
import jsonlines

dt = datetime.datetime.now()
dict_now = {'date': str(dt.date()), 'time': str(dt.time())}

with jsonlines.open('out.jsonl', mode='a') as writer:
    writer.write(dict_now)

print('updated: '+ str(dt))
```

処理させるとこんな感じでアウトプットが。

```
(venv) $ python dt2jsonl.py
updated: 2020-01-26 17:39:23.435616
(venv) $ cat out.jsonl
{"date": "2020-01-26", "time": "17:39:23.435616"}
```

`python dt2jsonl.py` のままcronに登録してみる。 `* * * * *`なので一分に一回処理されるはず。
エラーとprint結果を確認するため、`>> /tmp/cron.log 2>&1`でstderrとstdoutを/tmp/cron.logに書き出すようにする。


```
(venv) $ crontab -e
* * * * * python dt2jsonl.py >> /tmp/cron.log 2>&1
```

待っていると`/tmp/cron.log`にエラーが

```
(venv) $ tail -f /tmp/cron.log
python: can't open file 'dt2jsonl.py': [Errno 2] No such file or directory
```

`dt2jsonl.py`が見つからないらしいので、cronがどこにいるのか確認。

```
(venv) $ crontab -e
* * * * * pwd >> /tmp/cron.log 2>&1
```

```
(venv) $ tail -f /tmp/cron.log
/Users/[ユーザ]
```

ユーザディレクトリにいるので、スクリプトの絶対パスを教えてあげる。

```
(venv) $ crontab -e
* * * * * python /Users/[ユーザ]/[場所]/dt2jsonl.py >> /tmp/cron.log 2>&1
```

```
(venv) $ tail -f /tmp/cron.log
Traceback (most recent call last):
  File "/Users/[ユーザ]/[場所]/dt2jsonl.py", line 2, in <module>
    import jsonlines
ImportError: No module named jsonlines
```

今度はpythonスクリプトにたどり着いたが、jsonlinesがないと。venv環境で実行されてないので、cronはどのpythonを使っているのか確認。

```
(venv) $ crontab -e
* * * * * which python >> /tmp/cron.log 2>&1; python -V >> /tmp/cron.log 2>&1
```

```
(venv) $ tail -f /tmp/cron.log
/usr/bin/python
Python 2.7.10
```

システムのpython2.7を使っているので、なんとかするべき。
どのpythonを使うべきかチェック。

```
(venv) $ which python
/Users/[ユーザ]/[場所]/venv/bin/python
```

venv下のpythonに書き換える。

```
(venv) $ crontab -e
* * * * * /Users/[ユーザ]/[場所]/venv/bin/python /Users/[ユーザ]/[場所]/dt2jsonl.py >> /tmp/cron.log 2>&1
```

ちょっと待つと、`/tmp/cron.log`にprintの結果がでた。

```
(venv) $ tail -f /tmp/cron.log
updated: 2020-01-26 17:48:00.924120
```

```
(venv) $ cat out.jsonl
{"date": "2020-01-26", "time": "17:39:23.435616"}
```

out.jsonlにもjsonlineとして書き出されていると思いきや、最初に手動で実行したもので、cronで実行された結果ではない。
ユーザディレクトリで実行されたので、ユーザディレクトリにあった。



```
(venv) $ cat ~/out.jsonl
{"date": "2020-01-26", "time": "17:48:00.924120"}
{"date": "2020-01-26", "time": "17:49:01.102146"}
{"date": "2020-01-26", "time": "17:50:00.278025"}
```

アウトプットの場所が違いますが、cronはvenv環境で処理してくれた。
pythonスクリプトのアウトプットを絶対パスで指定するのもいいですが、
今回はcronの実行ディレクトリを変える。

```
(venv) $ crontab -e
* * * * * cd /Users/[ユーザ]/[場所]; venv/bin/python dt2jsonl.py >> /tmp/cron.log 2>&1
```

これで期待通りになった。

```
(venv) $ tail -f /tmp/cron.log
updated: 2020-01-26 17:55:00.837256
```

```
(venv) $ cat out.jsonl
{"date": "2020-01-26", "time": "17:39:23.435616"}
{"date": "2020-01-26", "time": "17:55:00.837256"}
```

ちょっと待つと

```
(venv) $ cat out.jsonl
{"date": "2020-01-26", "time": "17:39:23.435616"}
{"date": "2020-01-26", "time": "17:55:00.837256"}
{"date": "2020-01-26", "time": "17:56:00.986909"}
{"date": "2020-01-26", "time": "17:57:01.167183"}
{"date": "2020-01-26", "time": "17:58:00.273073"}
```