GAEでPython2.7を使ってthreadsafeを有効にする
なんだか解りづらいからメモ。
目的
本番サーバで、マルチスレッドで動かす。
開発サーバでも動くようにする。(残念ながらシングルスレッド)
データストアはHigh Replication datastore必須
Python2.7を使う場合、データストアはHigh Replication datastore(HRD)でなければならない。
Master/Slaveで作られたアプリの場合、HRDに移行する必要がある。
HRDへの移行はこの辺を参照。
Administering Your Datastore (Experimental) - Google App Engine - Google Code
http://code.google.com/intl/ja/appengine/docs/adminconsole/datastoreadmin.html
webapp2ライブラリ
webapp2とwebapp2_extrasをアプリのルートディレクトリに置く。
GAE本番サーバでは、google.appengine.ext.webappはwebapp2のエイリアスだけど、開発サーバはwebapp1が入ってる。
webapp1の機能しか使わないのであれば入れなくてもいい。
でもwebapp2.Routeとかの便利機能があるから入れておいたら幸せになれるはず。
Welcome to webapp2! — webapp2 2.3 documentation
http://webapp-improved.appspot.com/
app.yaml
Python2.5の時と書き方が若干違う。
一番解りづらいのはscriptの部分。
threadsafeを有効にした場合、Python2.5のように、/\.py$/を指定すると、以下の例外が発生してアプリを起動出来ない。
Invalid object: threadsafe cannot be enabled with CGI handler: main.py
最初、main.pyをmain.appにリネームすればいいのかなーとか思ったけど全然違った。
以下のようにした場合、main.pyファイルの、変数appを使う、という指定になる。
application: myapp version: 1 runtime: python27 api_version: 1 threadsafe: true handlers: - url: /favicon\.ico static_files: favicon.ico upload: favicon\.ico - url: /.* script: main.app
main.py
app.yamlで指定したように、main.pyにapp変数を作る。
app変数は、webapp2.WSGIApplicationのインスタンスでなければならない。
このapp変数は、グローバル変数として定義する必要がある。
サーバは、このapp変数を複数スレッドで使いまわす。
main()とかはいらない。
example
import webapp2 as webapp class MainHandler(webapp.RequestHandler): def get(self): self.response.out.write('Hello world!') app = webapp.WSGIApplication( [ ('/.*', MainHandler), ], debug=True)
開発サーバで動かない
開発サーバでは、まだPython2.7がサポートされてない。
Warning! The development web server, dev_appserver.py, included in the SDK does not yet support Python 2.7. In order to test your application on Python 2.7 you must deploy it using appcfg.py.
開発サーバを起動してアクセスすると、ImportErrorが発生する。
<type 'exceptions.ImportError'>: Could not find module main.app
args = ('Could not find module main.app',)
message = 'Could not find module main.app'
開発サーバで動かす
マルチスレッドで動かなくてもいいから、とりあえず開発サーバで表示だけはしたい。
その為に、こうする。
本番サーバでは、main/__init__.pyのapp変数を見に行かせる。
開発サーバでは、main/app.pyを実行させる。
これで両環境「script: main.app」の設定で動く。
main.py を main/__init__.py に移動し、mainをパッケージにする。
main/app.py は main/__init__.py のシンボリックリンク。
mkdir main mv main.py main/__init__.py ln -s __init__.py ln -s __init__.py main/app.py
main/__init__.py
main()とその実行部分を追記。
import webapp2 as webapp class MainHandler(webapp.RequestHandler): def get(self): self.response.out.write('Hello world!') app = webapp.WSGIApplication( [ ('/.*', MainHandler), ], debug=True) def main(): from google.appengine.ext.webapp import util util.run_wsgi_app(app) if __name__ == '__main__': main()
tree
ディレクトリ構成はこんな感じ。
.
├── app.yaml
├── index.yaml
├── main
│ ├── __init__.py
│ └── app.py -> __init__.py
├── webapp2.py
└── webapp2_extras
├── __init__.py
├── appengine
│ ├── __init__.py
│ ├── auth
│ │ ├── __init__.py
│ │ └── models.py
│ ├── sessions_memcache.py
│ ├── sessions_ndb.py
│ └── users.py
├── auth.py
├── config.py
├── i18n.py
├── jinja2.py
├── json.py
├── local.py
├── local_app.py
├── mako.py
├── protorpc.py
├── routes.py
├── securecookie.py
├── security.py
├── sessions.py
├── sessions_memcache.py
├── sessions_ndb.py
└── users.py
参考URL
Using Python 2.7 - Google App Engine - Google Code
http://code.google.com/intl/ja/appengine/docs/python/python27/using27.html
What's New in Python 2.7 - Google App Engine - Google Code
http://code.google.com/intl/ja/appengine/docs/python/python27/newin27.html