GIG

赴くままに技術を。

SwaggerでWeb APIを作る - 非同期実行 (その1)

これまでは同期処理(リクエストを送ると処理が実行され、レスポンスが返答されるまで待つ処理)であったが、処理が長いものなどは非同期で処理を実行しなくてはならない。PythonではCeleryというライブラリで実現できる。 ここではまず環境構築(Flask, Celeryの連携確認)まで行う。

Celeryとは

  • 非同期のタスク/ジョブキュー管理が可能
  • 複数のBrokerをサポート
    • RabbitMQが推奨
  • Result Backendをしているするとタスクのステータスや実行結果を取得可能
  • OpenStackでも採用実績あり

インストール

前提の環境としては、CentOS7を用いる。これをVirtualBox+Vagrantで環境から用意する。

$ vagrant init centos/7
$ 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
  • Pythonのインストール
    • Pythonのバージョンを切り替えやすいため、anyenv(pyenv)で入れておく
$ 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を使う

以下の順番で公式チュートリアルを読んでから手を動かし始めた

  1. First Steps with Celery
  2. Celery Based Background Tasks

ほとんどチュートリアル通りの内容。

celery_flask.py

config.py

app.py

次にこれを実行するが、その前に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