Hatena::ブログ(Diary)

作業記録/備忘録(仮) このページをアンテナに追加 RSSフィード

2012/08/03

apache + wsgi + djangoでのdebug方法

※「wsgiファイルにdebugger起動の設定を書いておく」を追記し、「link」に関連するポインタを追記しました。2012/08/05

概要

apache + wsgi + djangoを利用している時、pdbを利用したdebug方法について示します。

背景

djangoでdebugしていて、通常であればmanager.py runserverなどで確認していたが、事情によりapacheでの動作中に確認する必要があった。
簡単なところは、print debugしていたが、だんだん辛くなり、debuggerを利用する方法について調べたら分かったので備忘として残しておきます。

環境

OS CentOS 6.0
python 2.6.6
mod_wsgi 3.3
apache 2.2.15

(1)wsgiファイルにdebugger起動の設定を書いておく

djangoのprojectディレクトリ(setting.pyとかあるところ)にあるxxx.wsgiファイルにclass Debugerの設定と、applicationに適用する設定を書いておく。
個の記載をすることで、applicationが呼ばれる際にdebuggerを起動できる。

下記例では、class Debugger(object):以降の部分が追記する部分。

# cat ../gui/django.wsgi
import os, sys
sys.path.append('/var/www/xxx')
os.environ['DJANGO_SETTINGS_MODULE'] = 'gui.settings'

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

class Debugger(object):
    def __init__(self, object):
        self.__object = object

    def __call__(self, *args, **kwargs):
        import pdb, sys
        debugger = pdb.Pdb()
        debugger.use_rawinput = 0
        debugger.reset()
        sys.settrace(debugger.trace_dispatch)

        try:
            return self.__object(*args, **kwargs)
        finally:
            debugger.quitting = 1
            sys.settrace(None)

application = Debugger(application)

(2).htaccessをdebugしたいprogramのあるdirectoryに配置する

PythonHandlerのところに、debuggerを起動させたいprogramを指定する(?)。<--ちゃんと調べてません
下記例では、yyy.py

 AddHandler python-program .py
 PythonHandler yyy.py
 PythonEnablePdb On

(3)debugger起動待ち状態にする

 # apachectl -k stop
 # apachectl -DONE_PROCESS

プロンプトが戻ってこなくなり、pdb起動待ちになります。

(4)web accessすると、debuggerが起動するのでそのままdebugをすすめる。

[root@xxx XxxYyy]# apachectl -DONE_PROCESS   <--ここで待ちになるが、web browserアクセスしたら返ってくる
> /usr/lib/python2.6/site-packages/Django-1.4.1-py2.6.egg/django/core/handlers/wsgi.py(213)__call__()
-> if self._request_middleware is None:
(Pdb) l
208  	    request_class = WSGIRequest
209  	
210  	    def __call__(self, environ, start_response):
211  	        # Set up middleware if needed. We couldn't do this earlier, because
212  	        # settings weren't available.
213  ->	        if self._request_middleware is None:
214  	            self.initLock.acquire()
215  	            try:
216  	                try:
217  	                    # Check that middleware is still uninitialised.
218  	                    if self._request_middleware is None:
(Pdb) b /var/www/xxx/yyy.py:39
Breakpoint 1 at /var/www/xxx/yyy.py:39
(Pdb)

link

Mod_pythonアプリケーションpdbデバッグ
http://www.daemonfreaks.com/blog/200705281740.html

Debugging Techniques
http://code.google.com/p/modwsgi/wiki/DebuggingTechniques

2012/07/11

celeryを使う(CentOS)

概要

Celery(セロリ)は、非同期処理を行うタスクキュー/ジョブキューで、メッセージブローカーと呼ばれる、メッセージ送受信する仕組みと組み合わせて使用する。
メッセージブローカーは、RabbitMQ、Redis、Databaseなどから選択できるが、お勧めは、RabbitMQらしい。

Celeryの説明〜本家サイトより〜

Celery is an asynchronous task queue/job queue based on distributed message passing. It is focused on real-time operation, but supports scheduling as well.
The execution units, called tasks, are executed concurrently on a single or more worker servers using multiprocessing, Eventlet, or gevent. Tasks can execute asynchronously (in the background) or synchronously (wait until ready).


背景

非同期処理を仲介する、ありもののmodule/applicationとして、celeryの調査を行った。
pythonでは、multi thread処理ではGILの問題があるので、当初multiprocessing moduleを利用して複数process化(worker)+server化+queueを用意、などを考えていた。
結論としては、今回の用途にはceleryを使えば一発で済む。
また、設定も比較的容易にできた。
上記のような目的の場合であれば、celeryを使えば容易に済んだので、そういった方は利用を検討してみてもいいかもしれない。

以下の設定手順では、RabbitMQ+Celeryでの動作例を記載する。




以下の設定手順では、RabbitMQ+Celeryでの動作例を記載する。

設定手順

erlang*1rabbitmq-serverのinstall

repositoryの設定

# wget http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/x86_64/epel-release-6-7.noarch.rpm
# rpm -ivh epel-release-6-7.noarch.rpm 

erlangのinstall

# yum install erlang

rabbitmq-serverのinstall

# wget http://www.rabbitmq.com/releases/rabbitmq-server/v2.8.4/rabbitmq-server-2.8.4-1.noarch.rpm
# rpm -ivh rabbitmq-server-2.8.4-1.noarch.rpm

serverの起動

# service rabbitmq-server start
celeryの設定

celeryのinstall

# yum install gcc
# yum install python-devel 
# easy_install celery

celeryのサンプルコードと起動

セロリアプリとして、tasks.pyを以下のように用意する。(以降、本家チュートリアルより)

from celery import Celery

celery = Celery('tasks', broker='amqp://guest@localhost//')

@celery.task
def add(x, y):
    return x + y

作成したtasks.pyを呼び出してceleryを起動する。
workerとしてプログラムを動作させる。

$ celery -A tasks worker --loglevel=info

celery_test.pyとして以下を作成する。
delay()メソッドを使うことで、celeryを使える。

#! /usr/bin/env python
# -*- coding: utf-8 -*-
from tasks import add
add.delay(4, 4)

実行する。

$ ./celery_test.py

すると、celeryを起動したconsoleで、以下のように出力され、実行されたことがわかる。
log末尾に計算結果の"8"が見える。

[Tasks]
  . tasks.add

[2012-07-12 01:45:22,873: WARNING/MainProcess] celery@localhost.localdomain has started.
[2012-07-12 01:45:27,038: INFO/MainProcess] Got task from broker: tasks.add[d4ccee7e-2f4a-4f75-84fc-e91846bfe6f9]
[2012-07-12 01:45:27,052: INFO/MainProcess] Task tasks.add[d4ccee7e-2f4a-4f75-84fc-e91846bfe6f9] succeeded in 0.000603914260864s: 8

先の、tasks.pyにtime.sleep(3)等を入れると、celery_test.pyとtasks.pyが非同期に処理されることがわかる。(celery_test.pyはメッセージを投げてすぐ返る。tasks.pyはメッセージをceleryから受けて処理して返る。)

後日、djangoとの連携についても書きます。

リンク

本家:
http://celeryproject.org/
チュートリアル(わかりやすい):
http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html
rokujyouhitomaの日記([備忘録]DjangoCelery、RabbitMQの設定。):
http://d.hatena.ne.jp/rokujyouhitoma/20100625/1277477730

*1erlang(アーラン)とは、「コンピュータにおいて汎用的な用途に使うことができる並行処理指向のプログラミング言語および実行環境」とのこと。http://ow.ly/caBTG RabbitMQはerlangで実装されている。