Docker-compose 使うとき不便だったので作ってみました。
なにこれ
Database の接続が確立するまで待ち続けるだけの Python コマンドです。
dj_database_waiter myproject.settings
Django の設定モジュールを引数に渡してあげるだけで動きます。(厳密には止まります)
docker-compose で DB と Django 立ち上げた時、Dockerは最低限のネットワーク疎通ができるまで(?)は Django 側のコンテナの立ち上げを待ってくれますが、初期 SQL の投入だったりといった初期化まではしっかり待ってはくれません。
勝手に起動して勝手にコンテナが終了します。つらいめう
StackOverflow とかで対処法調べてもシェルスクリプトで準備するまで待つしかないみたいな事が書かれていて結構つらみがあります。
疎通確認のためだけに Python の Docker に DB Client をインストールしたくないですし…。
となると Python で疎通を確認するスクリプトを書くのがベターです。
ただプロジェクトごとにそのスクリプトをコピペしたり、Django とは別に都度接続情報を渡すのも面倒だなーと思ったのでコマンド化して pip で入るようにしてみました。
最初は Django コマンドとして admin.py から呼べるように実装したのですが、DB が立ち上がる前だとサブコマンドの起動自体失敗する事に気づいて泣く泣く普通のコマンドとして書き直しました。
使い道
version: '3'
services:
web:
build: .
command: python3 myproject/manage.py runserver 0.0.0.0:8000
volumes:
- .:/src
ports:
- 8000:8000
depends_on:
- db
db:
image: mysql
volumes:
- ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
- db-volume:/var/lib/mysql
volumes:
db-volume:
こういう docker-compose を up したときに一回で上手く立ち上がらない時は、ビルド時に dj_database_waiter をインストールするようにして
command: /bin/sh dj_database_waiter myproject.settings && python3 myproject/manage.py runserver 0.0.0.0:8000
みたいに command を置き換えてあげればよしなに1回で起動できるようになります。
おまけ: NamedTuple 楽しい
dj_database_waiter
は from typing.NamedTuple
を使いたかったためだけに Python3.6.1 以上を必要とします。あしからずご了承ください。
class DbStatus(NamedTuple):
ok: bool
reason: str = None
def check_status(db_group_name: str) -> DbStatus:
try:
...
except Exception as e: # NOQA
return DbStatus(ok=False, reason=str(e))
return DbStatus(ok=True)
引数2個なので NamedTuple 使う必要性ほぼ無いのですが、こんな風にわかりやすく書けます。
Scala でいう CaseClass に近いものですね。
型の情報も書いてるので IntelliJ みたいな IDE 使って書くとバリバリ補間・エラーチェックしてくれるので精神衛生上とてもよろしいです。
(ちなみに実行時型チェックはされないので、間違った型を入れても動いてしまいます)