[TurboGears] メンテナンス中のとき、別画面を表示する方法
環境
この記事の内容は、Ubuntu Linux 6.10, TurboGears 1.0.1で確認しました。
概要
ウェブアプリケーションを運用していると、例えばデータベースのスキーマを変更しているときなど、他のユーザからはアクセスされたくないときがあります。そんなとき、メンテナンス中である旨を表示する画面に、すべてのアクセスをリダイレクトできると便利です。この記事では、TurboGearsでそれを実現する方法を紹介します。
仕様
この機能の仕様は、次のようにします。
1. メンテナンス中のときは、カレントディレクトリにmaintenanceという名前のファイルを作成する。
2. カレントディレクトリにmaintenanceという名前のファイルがあるとき、/static/maintenance.htmlにすべてのアクセスをリダイレクトする。
コード
以下のコードを記述します。ファイルは、proj/filters/__init__.pyとします。
# -*- coding: utf-8 -*- from turbogears import url from cherrypy.filters import basefilter import os.path import cherrypy class MaintenanceFilter(basefilter.BaseFilter): def __init__(self, redirect_to=None, except_path=None): if redirect_to is not None: self.redirect_to = redirect_to else: self.redirect_to = "/static/maintenance.html" if except_path is not None: self.except_path = except_path else: self.except_path = ["/static"] def before_main(self): if not os.path.exists("maintenance"): return redirect = True for path in self.except_path: if cherrypy.request.path.startswith(url(path)): redirect = False break if redirect: raise cherrypy.HTTPRedirect(url(self.redirect_to)) # vim: tabstop=4 shiftwidth=4 expandtab
Rootコントローラに、以下のコードを記述します。
import proj.filters class Root(controllers.RootController): _cp_filters = [proj.filters.MaintenanceFilter()]
以上です。
詳細
CherryPyがリクエストを処理するコードは、/usr/lib/python2.4/site-packages/CherryPy-2.2.1-py2.4.egg/cherrypy/_cphttptools.pyの、Requestクラスの_runメソッドです。
def _run(self): try: # This has to be done very early in the request process, # because request.object_path is used for config lookups # right away. self.processRequestLine() try: applyFilters('on_start_resource', failsafe=True) try: self.processHeaders() applyFilters('before_request_body') if self.processRequestBody: self.processBody() # Loop to allow for InternalRedirect. while True: try: applyFilters('before_main') if self.execute_main: self.main() break except cherrypy.InternalRedirect, ir: self.object_path = ir.path applyFilters('before_finalize') cherrypy.response.finalize() except cherrypy.RequestHandled: pass except (cherrypy.HTTPRedirect, cherrypy.HTTPError), inst: # For an HTTPRedirect or HTTPError (including NotFound), # we don't go through the regular mechanism: # we return the redirect or error page immediately inst.set_response() applyFilters('before_finalize') cherrypy.response.finalize() finally: applyFilters('on_end_resource', failsafe=True) except (KeyboardInterrupt, SystemExit): raise except: if cherrypy.config.get("server.throw_errors", False): raise cherrypy.response.handleError(sys.exc_info())
applyFilters関数は、CherryPyのコントローラに設定されているフィルタの、指定したメソッドを実行します。すなわち、
applyFilters('before_main')
というのは、フィルタのbefore_mainメソッドを呼び出すことを意味します。さて上のコードから、コントローラのメソッドからだけでなく、フィルタから例外cherrypy.HTTPRedirectを生成しても、リダイレクトされることが分かります。よって、冒頭のbefore_mainメソッドでリダイレクトするフィルタを記述すれば、希望する動作を実現できます。また、Rootコントローラにフィルタを設定しておけば、その下のすべてのURLにおいて、有効となります。