eventletでCometサーバ
eventletづいてるので、Cometサーバを書いてみたよ。
tinycomet.py at master from shnjp's tinycomet - GitHub
eventlet.wsgiを使って、200行ぐらいで簡単なのが書けました。楽しいですね。
使い方
python tinycomet.pyで起動して、 /update/<UUID>にPOSTするとデータを作成
% curl -v 'http://127.0.0.1:8090/update/hogehoge' -d mogemoge
...
< HTTP/1.1 201 Created
< X-Tc-Timestamp: 2
< Content-Length: 0
...
受け取るには、/wait/<UUID>
% curl -v 'http://127.0.0.1:8090/wait/hogehoge'
...
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
< X-Tc-Timestamp: 4
< Content-Length: 7
...
mogemoge
waitにsince=<timestamp>をつけると、その時間になるまで待ちます。
各レスポンスのヘッダにあるX-TC-Timestampが、そのデータの最終更新時刻になります。
timestampは論理時間なので、実世界の時刻とは関係ありません
% curl 'http://127.0.0.1:8090/wait/hogehoge?since=4' &
[1] 97027
# waitに入る
% curl -v 'http://127.0.0.1:8090/update/hogeoge' -d fugafuga
fugafuga[1] + done ....
ほかに、waitにtimeout=[timeout:float]を与えると、timeout秒待って408 Request Timeoutを返します。
また、updateにfinished=1を与えると、次のwaitが終わった後にデータを消します。またcontent_type=[mimetype]でContent-Typeを指定できます。デフォルトはapplication/octet-stream
いろいろ引っかかったところ
event(pyevent)はだめくさい
eventletのdefault hubからthread safeじゃないという理由でpyeventが外されていたのだけど、今回はsingle threadなので試してみた。 しかしうまくimport出来ないので諦め。trunkも、配布バージョン(2007年!!)もだめじゃった。
python2.6からkqueueが使えるそうなので、自分でHubを書くのがよいのかな。eventlet自体もtrunkは結構変わっているので見ないといけなさげ
- python2.6からはepoll、kqueueが使える - def mopemope(self, *args, kwargs):
- 17.1. select — Waiting for I/O completion — Python v2.6.4 documentation
WaitForMultipleObjectsがやりたい
waitのところは、グローバルなConditionを作って
# wait側
with _update_lock:
while data.last_update <= since:
_update_lock.wait(timeout)
# update側
with _update_lock:
_update_lock.notify_all()
とやっているので、捌くdataの数が増えると破綻すると思う。dataごとにイベントを持たせて、WaitForMultipleObjects()的なことがしたいのだけど、この枠組みではどうやるんだろう。オシエテエライヒト
/wait_multiはmultipart/*を吐くコードを書くのが面倒なので実装していない。