drubyで作る超適当なRackセッション

Rack::Session::Memcacheを参考にdrubyで同じようなことをやってみたら、意外と簡単にできてしまった。
あとは、セッション管理側に適切な排他制御を実装すれば、それなりに使えるかな。

セッションを保持するdrubyサーバ
drb_session_manager.rb:

require 'drb'

class DRbSessionManager
  attr_reader :pool
  def initialize
    @pool = {}
  end
  def set(session_id, session)
    @pool[session_id] = session
  end
  def get(session_id)
    @pool[session_id]
  end
end

DRb.start_service('druby://localhost:11211', DRbSessionManager.new)
sleep

drubyサーバにアクセスするRackのセッション
drbpool.rb:

require 'rack/session/abstract/id'
require 'drb'

module Rack
  module Session
    class DRbPool < Abstract::ID
      attr_reader :pool

      DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \
        :namespace => 'rack:session', :druby_server => 'druby://localhost:11211'

      def initialize(app, options={})
        super
        @pool = DRbObject.new_with_uri(@default_options[:druby_server])
      end

      def generate_sid
        loop do
          sid = super
          break sid unless @pool.get(sid)
        end
      end

      def get_session(env, session_id)
        unless session_id and session = @pool.get(session_id)
          session_id, session = generate_sid, {}
          @pool.set(session_id, session)
        end
        return [session_id, session]
      end

      def set_session(env, session_id, new_session, options)
        @pool.set(session_id, new_session)
        return session_id
      end
    end
  end
end

sinatraを使ってセッションのテスト
main.rb:

require 'sinatra'
require './drbpool'

use Rack::Session::DRbPool

get('/') do
  session[:count] = (session[:count] || 0) + 1
  "count: #{session[:count]}"
end

実行してみる。

hiro@neptune% ruby drb_session_manager.rb &
[1] 4144
hiro@neptune% ruby main.rb
== Sinatra/1.1.2 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.2.7 codename No Hup)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop

別ターミナルで。

hiro@neptune% curl --cookie-jar cookie.txt http://localhost:4567
count: 1
hiro@neptune% cat cookie.txt
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_localhost     FALSE   /       FALSE   0       rack.session    d0673073b2f257040f22a0757d3e67f8
hiro@neptune% curl --cookie rack.session=d0673073b2f257040f22a0757d3e67f8 http://localhost:4567
count: 2
hiro@neptune% curl --cookie rack.session=d0673073b2f257040f22a0757d3e67f8 http://localhost:4567
count: 3

DRbSessionManagerの中身を確認してみる。

hiro@neptune% irb
irb(main):001:0> require 'drb'
=> true
irb(main):002:0> d = DRbObject.new_with_uri('druby://localhost:11211')
=> #<DRbSessionManager:0x10164bc0>
irb(main):003:0> d.pool
=> {"d0673073b2f257040f22a0757d3e67f8"=>{:count=>3}}
irb(main):004:0>