IRCログを貼付け

nishio: @admin_requiredなビューにアクセスしたときに

google.appengine.ext.db.KindError
KindError: No implementation for kind 'main_user'

が出ることがあるのですが再現する方法がまだ見つかってません。特に何も修正していなくても久しぶりにアクセスすると出るように見えて、「いまどういうユーザとしてログインしているのか」を表示するためのビューが叩かれた後で同じURLにアクセスするとエラーにならずに見えるので、セッションのexpirationに関係する挙動かなと疑っています。問題の行は

File "…/kay/auth/backends/datastore.py", line 42, in get_user
return db.get(request.session['_user'])

です。本番サーバでも同じ現象がおきます。

セッションのexpirationにしては早い。なにかをしてしまったときにセッションがおかしくなるのだろうか。

_tmatsuo: nishio: ありがとうございます。ちょっと心当たりがあるので調べてみます。ローカルで runserver 後にまず /_ah/admin にアクセス -> アプリにアクセスとかやると起こったりするような気がしている。Model の衝突を避けるために appname_modelname という風に kind を上書きしてるんですが、それが諸悪の元ですww もうデフォルトでは Off にしてしまおうかなと思っていますが。ちなみに settings.ADD_APP_PREFIX_TO_KIND を False にするとこの挙動をしなくなるのでそのエラーは出なくなると思います。ただし今までのデータにはアクセスできなくなるので注意してください


nishio: うーむ。main_userとuserの両方にアクセスできるならBulk Updateとかで簡単に移行できるのでしょうけど、たぶん同時にはアクセス出来ないんですよね、settingsで決まっているし。実は手元の挙動では@admin_requiredな/adminにアクセスして、成功すると、次の/adminへのアクセスで確実に発生して@no_sessionではない/login_infoにアクセスして、それから/adminにアクセスするとたぶん100%成功するんですよ。なので/adminの中からAjaxで/login_infoにGETを投げればいいんじゃないかなーという全く本質的じゃないワークアラウンドを考えています。


nishio: あれー、一晩寝たら昨日と挙動が違う…(ぇ
nishio: エラーが起きなくなってしまった…
mopemope: お、session?
nishio: @admin_requiredなビューにアクセスしたときに

google.appengine.ext.db.KindError
KindError: No implementation for kind 'main_user'

/kay/auth/backends/datastore.py", line 42, in get_user
return db.get(request.session['_user'])

ででるという問題です。ログを何処かに貼りつけようかな。


mopemope: ごった煮なってるのかな。これに似た話?? http://code.google.com/p/googleappengine/issues/detail?id=1133
nishio: リンク先を読んでいるナウ。Kindを検索するときのキーがバイト列であるべきなのにユニコードだったせいで見つからなかったということですね、なるほど。エラーメッセージが%sで表示されているからunicodeになってても分からない。とりあえずlogging.debug(type(kind))とか挟んで再現するのを待つかな…
mopemope: ソース全く見てないけど、たぶんその辺が怪しいのかなと。VPNつなぐのでオチ


nishio: エラーになる時にはtypeがunicode、エラーにならないときにはclass_for_kindがそもそも呼ばれていない。普段の操作をしているとclass_for_kindがそもそも呼ばれないのでunicodeなのが正しいのかおかしいのか確認できない。

nishio: うーん、正しい時もエラーの時もrequest.session['_user']はdatastore_types.Key.from_path(u'main_user', 144L, _app=u'foobar')。unicodeなのは同じ。_kind_mapのキーがstrなのでclass_for_kindにunicodeを渡してはいけない。
mopemope: 動いたり動かなかったりってのがよくわからんな
nishio: そう。なんかキャッシュされてるのだろうか。動いたり動かなかったりする要素が見つからない。とりあえずclass_for_kindの冒頭で「kindがunicodeだったらstrに変換」ってするだけで問題は解決するけど、別の大きな問題を悪質化させてしまうだろうなぁ



_tmatsuo: kay.auth.backends.datastore.DatastoreBackend の __init__ 一行目にimport_string(settings.AUTH_USER_MODEL)を入れれば大丈夫な気がする。Python の dict の key は unicode/str どちらでもアクセス可能みたいなので、問題は別のところにあるぽいです。key により db.get しているので、それ以前に Model 定義を import しておく必要があっただけの話だと思われます。サーバー側で現象が起きるケースと起きないケースとある件ですが、ログイン画面を通って、ログイン処理をした server instance 上ではそのプロセス内で main.models.User が import されています。このインスタンスが生きている間は大丈夫(エラーは起きない)で、このインスタンスがメモリから追い出されると、問題になっているエラーが出るというわけです。