@m_seki の

I like ruby tooから引っ越し

4th Drip Developers Conference

世界中のDrip開発者のだいたい80%が一堂に会す、DDCが行われました。世界最大のDrip開発者のイベントです。

今回のテーマは時間とともに変化するデータ(電力消費量)を集めてきて可視化(今回は時系列のグラフ表示)するまでの具体的なコードのコードレビューでした。このシステムでは主に3個の処理が動きます。

  • MyDrip - Dripのサーバ。ホームディレクトリにストレージを用意し、UNIXドメインのソケット経由でサービスします。
  • Fetcher - 定期的(三分間隔)にWebページをスクレイピングしてMyDripにデータを書き込む係。
  • Reporter - 直近の20個のデータ(一時間分)をMyDripからreadし、グラフを返す係。グラフはGoogle Chart APIを使って実装していて、Reporterが返すのはGoogle Chart APIのURLです。
  • CGI - グラフの画像を返すためのCGI。Reporterに質問して求めたURLへリダイレクトするだけ。

MyDripは他のアプリケーションでも使っている、いつものアレをそのまま利用します。

# 以下疑似コードで説明するけども記憶だけを頼りに書いているので間違ってるかもしれないし、そのままでは動かないですよー。

Fetcherの疑似コードは次のような無限ループです。Webページからデータを作ってはMyDrip.writeするだけ。# 具体的なスクレイピングのあたりはsnipped。

while true
  tuple = Hash.new
  body = open("http:....")
  tuple['at'] = Time.now
  # 正規表現でデータ探してきてメモする
  MyDrip.write(tuple, "Electric Power")
end

Reporterの疑似コードは次のような簡単なメソッドです。MyDripの先頭から20個、'Electric Power'とタグがついている情報を取り出し、そこからGoogle Chart APIのURLを組み立てて返します。

def make_url
  tuple = MyDrip.head(20, 'Electric Power')
  tuple.each do |k, v|
    ...
  end
   ....
end

Fetcherは無限ループでデータを集め続け、ReporterはCGIに備えてdRubyのサービスとする必要があります。どちらもデーモンとして動かす必要があるわけですが、二つのプロセスを管理するのが面倒だったので、今回は一つのプロセスにまとめました。ほんとは別のほうが便利です。

DRb.start_service('druby://localhost:55443', Reporter.new)
Fetcher.new.main_loop

いつもならDRb.start_serviceのあとにsleepなり、DRb.thread.joinなりを書く部分にFetcherのmain_loopを置きました。

CGIはだいたいこんな疑似コードです。

require 'drb'
url = DRbObject.new_with_uri('druby://localhost:55443').make_url
puts "Location: #{url}\r\n\r\n"

ふつうに考えたら、ReporterはCGIに載せるべきだと思うんだけど、MyDripはホームディレクトリにあるUNIXドメインのソケットでサービスしてるので、CGIの権限ではアクセスできないのでした! DripサーバをTCPにしたらCGIにReporterを配置させるといいと思う。

情報はFetcherで更新されて、グラフは要求のあったときに更新される。ViewはViewの都合で更新するだけ。お互いの更新のタイミングは全然関係がないのでした。

全部で90行前後(空行込み)。 ちっちゃいプロセスが協調する様子が伝わったかなあ。