
独自ドメインを使ってGoogle App Engineで運用しているサイトがあって、cronがうまく動かずにかなりハマりました。なんとか解決できたので、私がやった解決法を書いておきます。
同じような症状でエラーが出ている人はあまりいないと思いますが、もし当てはまったら参考にして下さい。
環境はだいたい以下のとおり。
- Google App Engine
- Python 2.7
- 独自ドメイン(カスタムドメイン)で運用
- SSL対応
- Django 1.5
設定はうまくできてるはずなのにcron jobsが起動すると失敗するという症状が出ました。
ブラウザで直接URLを入力すると問題なく動いているのに、cronで動かすとなぜか失敗になってしまいます。
ログを調べてみるとcronでのアクセスのHTTPステータスコードが301になっている。他方でブラウザでURLを入力してアクセスした場合には200になっている。
GAEのcron jobsは、HTTPステータスコードを200番台で返さないとエラーになるということは知ってたので、301が返ってきている以上は失敗するというのは分かります。
でも、なぜ301リダイレクトになるのかが全く分かりませんでした。
かなり苦労して分かった原因は、Djangoのsettings.pyのMIDDLEWARE_CLASSESに設定していたSSLRedirectの設定でした。
そんな設定をしてたのをすっかり忘れてたけど、グーグルが全てのサイトでSSL対応することを推奨し始めた数年前に自分で設定してたのです。
せっかくSSL対応したのだからセキュリティのためとSEOのためにhttpに来たアクセスを自動で全てhttpsに301リダイレクトするために、sslmiddlewareを設定していたのです。
参考URL
具体的にはDjangoのsettings.pyのこの部分です。
MIDDLEWARE_CLASSES = (
.........
.........
'appname.middles.sslmiddleware.SSLRedirect',
)
cron.yamlにターゲットを設定をしてない場合、cronが起動するとデフォルトのバージョンのURLにアクセスが発生します。
このデフォルトのバージョンというのは、ログを見てみると独自ドメインで運用している場合でも、最初に与えられるドメインであるappspot.comの方です。
しかも、httpsではなく、httpの方にアクセスが発生します。
例えば、以下のような設定で独自ドメインを使っている場合。
- デフォルトのドメイン(http) -> http://appname.appspot.com/
- デフォルトのドメイン(https) -> https://appname.appspot.com/
- 独自ドメイン(http) -> http://www.appname.com/
- 独自ドメイン(https) -> https://www.appname.com/
1と2は最初にデフォルトで与えられるドメインで、httpでもhttpsでもどちらでもアクセスできるようになっていると思います。
私の場合はそれに独自ドメインを設定して、SSL対応しているので4を中心に運用しています。
先ほどのsslmiddlewareを使って、3のhttpへのアクセスを全て自動的に4のhttpsの方に301リダイレクトしていました。
この様な設定の状態の時にcronが起動すると、1の指定したパスにアクセスが発生します。
するとsslmiddlewareによって自動的に2のhttpsの方に301リダイレクトが発生してしまうのです。
これが原因で、cronが失敗していたのです。
これを解決するためには、cronで起動するパスに対してだけ301リダイレクトをさせないという設定をする必要があります。
urls.pyにcronで起動させるパスを記述して、新たに別のssl_urls.pyというファイル作って残りを全て分離してそちらに移しました。
そして、分離したssl_urls.pyをincludeで呼び出し、それに{'SSL':True}を設定しました。
これでcronで起動させるパスに対しては301リダイレクトが生じずに、それ以外のパスに対しては301リダイレクトが生じるという設定になります。
このように設定してようやくcronで動かしても200が返ってきて無事に動きました。
urls.pyはこんな感じです。
urlpatterns = patterns('',
# Cron
(r'^cron/example/$', cron_example),
(r'^cron/........),
# SSL
(r'^.*?', include(appname.ssl_urls), {'SSL':True}),
)
注意が必要なのは「r'^.*?',」の部分です。最後に$が要りません。最後に$をつけるとどこのパスにアクセスしてもトップページが表示されるというおかしな事になってしまいました。
結局、すごく簡単で単純な事が原因だったので、同じような失敗をしている人はほとんどいないと思いますが、参考にしてみて下さい。