Class: Rack::Session::Memcache

Inherits:
Abstract::ID show all
Defined in:
lib/rack/session/memcache.rb

Overview

Rack::Session::Memcache provides simple cookie based session management. Session data is stored in memcached. The corresponding session key is maintained in the cookie. You may treat Session::Memcache as you would Session::Pool with the following caveats.

  • Setting :expire_after to 0 would note to the Memcache server to hang onto the session data until it would drop it according to it’s own specifications. However, the cookie sent to the client would expire immediately.

Note that memcache does drop data before it may be listed to expire. For a full description of behaviour, please see memcache’s documentation.

Constant Summary collapse

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

Instance Attribute Summary collapse

Attributes inherited from Abstract::ID

#default_options, #key

Instance Method Summary collapse

Methods inherited from Abstract::ID

#call, #context

Constructor Details

#initialize(app, options = {}) ⇒ Memcache

Returns a new instance of Memcache.



28
29
30
31
32
33
34
35
# File 'lib/rack/session/memcache.rb', line 28

def initialize(app, options={})
  super

  @mutex = Mutex.new
  @pool = MemCache.
    new @default_options[:memcache_server], @default_options
  raise 'No memcache servers' unless @pool.servers.any?{|s|s.alive?}
end

Instance Attribute Details

#mutexObject (readonly)

Returns the value of attribute mutex.



23
24
25
# File 'lib/rack/session/memcache.rb', line 23

def mutex
  @mutex
end

#poolObject (readonly)

Returns the value of attribute pool.



23
24
25
# File 'lib/rack/session/memcache.rb', line 23

def pool
  @pool
end

Instance Method Details

#generate_sidObject



37
38
39
40
41
42
# File 'lib/rack/session/memcache.rb', line 37

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

#get_session(env, sid) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rack/session/memcache.rb', line 44

def get_session(env, sid)
  session = @pool.get(sid) if sid
  @mutex.lock if env['rack.multithread']
  unless sid and session
    env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil?
    session = {}
    sid = generate_sid
    ret = @pool.add sid, session
    raise "Session collision on '#{sid.inspect}'" unless /^STORED/ =~ ret
  end
  session.instance_variable_set('@old', {}.merge(session))
  return [sid, session]
rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted
  warn "#{self} is unable to find server."
  warn $!.inspect
  return [ nil, {} ]
ensure
  @mutex.unlock if env['rack.multithread']
end

#set_session(env, session_id, new_session, options) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rack/session/memcache.rb', line 64

def set_session(env, session_id, new_session, options)
  expiry = options[:expire_after]
  expiry = expiry.nil? ? 0 : expiry + 1

  @mutex.lock if env['rack.multithread']
  session = @pool.get(session_id) || {}
  if options[:renew] or options[:drop]
    @pool.delete session_id
    return false if options[:drop]
    session_id = generate_sid
    @pool.add session_id, 0 # so we don't worry about cache miss on #set
  end
  old_session = new_session.instance_variable_get('@old') || {}
  session = merge_sessions session_id, old_session, new_session, session
  @pool.set session_id, session, expiry
  return session_id
rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted
  warn "#{self} is unable to find server."
  warn $!.inspect
  return false
ensure
  @mutex.unlock if env['rack.multithread']
end