読者です 読者をやめる 読者になる 読者になる

Gearman UDFを試してみる(2)

Gearman Python SQLAlchemy

前エントリの続き。

SQLAlchemyを使ってテーブル・トリガーを定義

前々エントリで紹介した資料と全く同じテーブルとトリガーをSQLAlchemyを使って定義する。

# -*- coding: utf-8 -*-
# models.py
from sqlalchemy import *
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('mysql://scott:tiger@127.0.0.1/test?charset=utf8&use_unicode=0')

Session = scoped_session(sessionmaker(bind=engine))

Base = declarative_base(bind=engine)

class URL(Base):
    __tablename__   = 'url'
    __table_args__  = { 'mysql_engine': 'InnoDB' }

    id      = Column(Integer, primary_key=True)
    url     = Column(String(255), nullable=False)
    content = Column(BLOB)

## テーブル作成時に同時にトリガーを作成
url_get = DDL(
    """CREATE TRIGGER url_get
       BEFORE INSERT ON url
       FOR EACH ROW
       SET @ret=gman_do_background('url_get', NEW.url)""", on='mysql')
url_get.execute_at('after-create', URL.__table__)

if __name__ == '__main__':
    ## テーブルを作成
    Base.metadata.create_all()

SQLAlchemyでトリガーを定義する時には、

ddl = DDL("CREATE TRIGGER ...")

DDLオブジェクトを作って、

ddl.execute_at('after-create', table)

のように、execute_atでSQLAlchemyのDDLイベント(before-create, after-create, etc)に登録する。

上記のコードをmodels.pyとして保存し、

$ python models.py

で、テーブル・トリガーを作成。

Gearman Workerを書く

指定したURLの内容を取得するWorkerを書く。

ここではhttplib2を使った。あまりエラー処理は考慮していない。もとのPHPコードをそのままPythonに移しただけなので、urlカラムにIndexが引いていないとか、同じURLの行を上書きしてしまうとか、いろいろイケていない感じだけどサンプルコードとして深く考えないことにする。

# -*- coding: utf-8 -*-
import httplib2
from gearman import GearmanWorker

from models import URL, Session

def url_get(job):
    url = job.arg

    conn = httplib2.Http()
    headers, content = conn.request(url)

    #print url, len(content)
    Session.query(URL).filter_by(url=url).update({'content': content})
    Session.commit()


worker = GearmanWorker(["127.0.0.1:4730"])
worker.register_function("url_get", url_get)
worker.work()

試してみる

MySQLクライアントから、

mysql> insert into url(url) values
 -> ('http://www.python.org/'),
 -> ('http://www.gearman.org/'),
 -> ('http://www.sqlalchemy.org/');
Query OK, 3 rows affected (0.04 sec)
Records: 3  Duplicates: 0  Warnings: 0

しばらくしてから結果を確認する。

mysql> select url, length(content) from url;
+----------------------------+-----------------+
| url                        | length(content) |
+----------------------------+-----------------+
| http://www.python.org/     |           17191 |
| http://www.gearman.org/    |           21977 |
| http://www.sqlalchemy.org/ |           13341 |
+----------------------------+-----------------+
3 rows in set (0.00 sec)