SwaggerでWeb APIを作る - 非同期実行 (その1)
これまでは同期処理(リクエストを送ると処理が実行され、レスポンスが返答されるまで待つ処理)であったが、処理が長いものなどは非同期で処理を実行しなくてはならない。PythonではCeleryというライブラリで実現できる。 ここではまず環境構築(Flask, Celeryの連携確認)まで行う。
Celeryとは
- 非同期のタスク/ジョブキュー管理が可能
- 複数のBrokerをサポート
- RabbitMQが推奨
- Result Backendをしているするとタスクのステータスや実行結果を取得可能
- OpenStackでも採用実績あり
インストール
前提の環境としては、CentOS7を用いる。これをVirtualBox+Vagrantで環境から用意する。
$ vagrant init centos/7
- 5672, 15672のポートを開ける
- BrokerとしてRabbitMQを使用する
- 使用するポートはhttps://www.rabbitmq.com/install-rpm.htmlの"Port Access"参照。
$ cp Vagrantfile{,.bak} $ vim Vagrantfile ...(省略)... config.vm.network "forwarded_port", guest: 5672, host: 5672 config.vm.network "forwarded_port", guest: 15672, host: 15672 ...(省略)...
- 仮想マシンを起動する
$ vagrant up $ vagrant ssh
- rootパスワードは
vagrant
が初期値となっている
$ su - Password: # rpm -Uvh http://download.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-9.noarch.rpm'
- RabbitMQのインストールおよび自動起動設定を行う
# yum -y install rabbitmq-server # systemctl enable rabbitmq-server.service # systemctl list-unit-files -t service | grep rabbit rabbitmq-server.service enabled
$ sudo yum -y install git zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel xz xz-devel $ git clone https://github.com/riywo/anyenv ~/.anyenv $ echo 'export PATH="$HOME/.anyenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(anyenv init -)"' >> ~/.bash_profile $ exec $SHELL -l $ anyenv install pyenv $ exec $SHELL -l $ pyenv install 3.5.4 $ pyenv versions * system (set by /home/vagrant/.anyenv/envs/pyenv/version) 3.5.4 $ pyenv global 3.5.4 $ pyenv versions system * 3.5.4 (set by /home/vagrant/.anyenv/envs/pyenv/version)
- Celery, flaskのインストール
$ pip install celery flask
- RabbitMQの設定
- ユーザ, バーチャルホスト, ユーザタグ, 権限を設定
- 権限は、設定、読み書き全ての権限を付与
# rabbitmqctl add_user vagrant vagrant Creating user "vagrant" ... ...done. # rabbitmqctl add_vhost vagrant Creating vhost "vagrant" ... ...done. # rabbitmqctl set_user_tags vagrant vagrant_tag Setting tags for user "vagrant" to [vagrant_tag] ... ...done. # rabbitmqctl set_permissions -p vagrant vagrant ".*" ".*" ".*" Setting permissions for user "vagrant" in vhost "vagrant" ... ...done.
FlaskからCeleryを使う
以下の順番で公式チュートリアルを読んでから手を動かし始めた
ほとんどチュートリアル通りの内容。
次にこれを実行するが、その前にCeleryワーカーを起動していないくてはならない。celery worker
コマンドを使うとフォアグラウンドで実行するので、celery multi
コマンドを使って、バックグラウンドで実行する
$ sudo mkdir -p /var/run/celery $ sudo mkdir -p /var/log/celery $ sudo chown -R vagrant. /var/run/celery/ $ sudo chown -R vagrant. /var/log/celery/ $ celery multi start w1 -A app -l info --pidfile=/var/run/celery/%n.pid --logfile=/var/log/celery/%n%I.log
最後にターミナルをもう1つ開いてタスクが投げ込まれるかを見てみる。
- ターミナル1
$ python Python 3.5.4 (default, Aug 24 2017, 12:02:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from app import add_together >>> add_together.delay(1,3) <AsyncResult: 0ee3b370-561c-4e9f-a978-58635b00df89>
- ターミナル2
$ tailf /var/log/celery/w1-1.log ...(省略)... [2017-09-16 02:24:23,203: INFO/ForkPoolWorker-1] Task app.add_together[74dabaad-aa7e-4dee-aab1-a505deaeb76f] succeeded in 0.0009727960004966008s: 4