プラニングポーカーの場の情報(場名や参加プレイヤー名)をFlaskアプリケーションのトップレベルの変数に格納していたが、これだとHerokuにデプロイしたときにちゃんと動作しないので、Redisに永続化することにする。
ローカル環境ではDockerでRedisサーバを起動しよう。
version: '2'
services:
redis:
image: redis:latest
ports:
- "6379:6379"
command: redis-server --appendonly yes
volumes:
- ./data/redis:/data
上記のdocker-compose.yml
を用意し、コンテナをバックグラウンド実行で起動する。
$ docker-compose up -d
Pythonでアクセスするためのライブラリをインストール。
(venv) $ pip install redis
Herokuにデプロイするために依存ライブラリをrequirements.txt
に書き出しておく。
(venv) $ pip freeze > requirements.txt
現在のrequirements.txt
はこんな感じ。
click==7.1.1
Flask==1.1.1
Flask-SocketIO==4.3.0
gunicorn==20.0.4
itsdangerous==1.1.0
Jinja2==2.11.1
MarkupSafe==1.1.1
python-engineio==3.12.1
python-socketio==4.5.1
redis==3.5.0
six==1.14.0
Werkzeug==1.0.0
Flaskアプリケーションでインポート。
import redis
初期化。
# Redis
REDIS_URL = (
os.environ.get("REDIS_URL")
if os.environ.get("REDIS_URL") != None
else "redis://localhost:6379"
)
DATABASE_INDEX = 1
pool = redis.ConnectionPool.from_url(
REDIS_URL, db=DATABASE_INDEX, decode_responses=True
)
db = redis.StrictRedis(connection_pool=pool)
EX = 86400 # 1日
Herokuにデプロイすると環境変数REDIS_URL
に接続先URLがセットされているので、それを見るようにする(2-6行目)。
コネクションプールの初期化パラメータでdecode_responses
を指定し、自動デコードされるようにしておく(9行目)。
12行目の定数は、Redisに書き込んだデータの生存期限を表す定数(あとで使用する)。
データの書き込み。
table_id = str(uuid.uuid4())
player_id = 0 # 親は0とする
db.hset(table_id, "name", table_name)
db.hset(table_id, "players", parent_name)
db.expire(table_id, EX)
場のID(table_id
)をキーとして、複数の値を管理したいため、hset
関数を使って書き込む(3-4行目)。
その後expire
関数で生存期限を指定(5行目)。
データの読み出し。
table = db.hgetall(table_id)
table_name = table["name"]
players = table["players"]
hgetall
関数を使えばすべての属性をディクショナリで取り出せる(1行目)。
ローカルで動作するようになったので、Herokuにデプロイする。
その前に、gunicorn
のパラメータを変更しておきたい。デフォルトだと1ワーカープロセス、1スレッドなので完全直列処理になってしまう。
web: gunicorn app:app --workers 2 --thread 4 --log-file -
無料Dynoなのでこんなところか?
【2020-5-9追記】
gunicornで複数ワーカープロセス設定をすると、Flask-SocketIOで400 Bad Requestエラーが起こることが判明。詳細と対処方法は次回記事に記載。
あとはHerokuのWebコンソールからRedis
アドオンを追加しておいて(これもフリープランがあるので助かる!)、いつもどおりpush
すればOK。
$ git push heroku master
無事Redis
を使ったデータ永続化が実現できた。
ようやくアプリケーションのバーティカルスライスが通ったので、この先は機能を作り込んでいく。
コメント
[…] まず初めに前回の投稿で書いた以下の設定はNGだったので修正する。具体的には、WebSocket通信が一定数で404 Bad requestになってしまう現象が起こった。どうやらgunicornのロードバランシング機能がスティッキーセッションをサポートしていないのが原因らしい。 […]