ぱろっと・すたじお

技術メモなどをまったりと / my site : http://parrot-studio.com/

memcache-client と thin の競合 on Ruby1.9.1

TokyoCabinetを使った検索コアは出来上がったのですが、
作るべきはWebシステムなので、それをWeb側から叩かないといけません


しかし、JavaScriptで非同期にリソースを取得する仕組みだと、
そのURIさえわかればデータを自由に取得される恐れがあります
(今回はデータそのものが売り物なので、これだと困る)


リソースURIは正規のユーザが操作している間だけ有効なものですが、
その間に不正にデータを持っていかれる可能性は否定できません


そこで、リソース取得の仕組みに、
独自セッションによる認証を追加することにしました


Rails・・・というよりRackのセッションにこの仕組みを組み合わせ、
画面遷移とリソース取得で、透過的な認証処理を行うようにしたのです(`・ω・´) b


・・・というのが前置きで、ここから本題ですが、
この手のセッション情報の管理にmemcached*1を使うというのは、
最近ではごく一般的な手法だと思います


※以下の話は「ruby1.9.1」環境です


もちろんmemcached込みのRSpecは通過させまして、
Sinatra(0.9.6)で起動するテスト環境に組み込んでみたのですが、
memcachedへ接続するところで、「MemCache::EventedServer」がないと怒られたのです


該当するmemcache-clientのコードを見てみますと、
initializeの以下の部分で落ちてました

self.extend(MemCache::EventedServer) if defined?(EM) and EM.reactor_running?

この「EM」が何かって考えると、おそらく「EventMachine」のことだろうと
(ノンブロックI/Oのあれですね)


なぜEMが定義されたのかわかりませんが、とりあえずrequireを変更

#require 'memcache'
require 'memcache/event_machine'

これで「MemCache::EventedServer」が定義されたのですが、
今度は別なエラーがΣ(・ω・ノ)ノ

FiberError - can't yield from root fiber:

該当箇所は「Fiber.yield」しているので、
何かしらやってるんだとは思いますが、
エラーの意味も原因も全くわかりません


しかも、このエラーが出た後、
再度memcachedにアクセスする処理を走らせると、
なぜか正常に通ってしまうのです


さらに同じ処理を走らせると、
今度は「(よくわからない)パラメータがnil」とエラーになってもうお手上げ(´・ω・`)
Fiberを使ってることから、何かサイクル処理がおかしいのかも


ここでしばらく悩んだのですが・・・
考えてみればSinatra(0.9.6)がデフォルトでthin(1.2.7)を起動しており、
thinがeventmachineを使っているのです


おそらく、thinが定義した「EM」とmemcache-clientが競合し、
定義してないクラスを呼んだり、Fiberの処理をおかしくしたと思われます


これを確かめるため、Sinatraを「-s webrick」で起動すると、
見事に想定通りの動きをしました(`・ω・´) b
「require 'memcache'」でも「'memcache/event_machine'」でもOK


最終的に、このテスト環境はPassengerで動かすので、
Passenger(2.2.14)で起動してみると、やっぱり問題なく動きました


つまり、thinとの組み合わせの時だけおかしくなるわけですが、
Sinatra1.0だと修正されてるのでしょうか・・・


試したいところなのですが、Sinatra1.0はerbの処理がうまくいっておらず、
magic-commentつきのerbでも文字コードエラーで落ちてしまうのです
hamlで書いたものは文字コード指定できるので通るのですが・・・


・・・難しいですね(´・ω・`)

*1:あるいは互換インターフェースを持つ分散KVSなど