Memcache, sessions, fragments, oh my!


#1

Hi all -

I am trying to get rails to use memcache for sessions and fragment
caching. I’d also like to use the same connection for general caching
of
this and that.

I’m following the instructions here:
http://wiki.rubyonrails.com/rails/pages/HowtoChangeSessionStore

and hitting a brick wall.

I’m using the new memcache-client since from what I’ve read it’s faster,
but it’s implementation is different enough that I can’t figure out how
to
make it work with:

config.action_controller.session_store = :mem_cache_store
config.action_controller.fragment_cache_store = :mem_cache_store

I’ve got this in environment.rb as well:

MEMCACHE_OPTIONS = {
  :compression => false,
  :debug => false,
  :namespace => "#{RAILS_ENV}",
  :readonly => false,
  :urlencode => false
}
MEMCACHE_SERVERS = [ '192.168.1.20:11211' ]

and if I leave everything else out and run script/console I can use
those
defines to create a Memcache object, but I have no idea how to get that
same instance to be used for session_store and fragment_cache_store.

Anyone want to share their config? Or tell me to go back and use
RubyMemcache instead?

Thanks!

-philip


#2

Anyone want to share their config? Or tell me to go back and use
RubyMemcache instead?

I described my config here

http://blog.innerewut.de/articles/2006/02/09/time-based-fragment-caching-with-memcache

I use the newer memcache-client for sessions and fragments and had no
problems so far.

Jonathan


#3

Jonathan,

Thanks for the info. I had a longer reimplementation of the
MemCacheStore
just because I don’t know Ruby enough (namespaces and all that). I can’t
seem to make memcache work for my session, though. I have set your code
in
environments/development.rb (want to test if before moving to
production). I
keep getting errors about user class/module not found. Any ideas why?

Thanks,

Adrian M.


#4

Adrian M. wrote:

Jonathan,

Thanks for the info. I had a longer reimplementation of the
MemCacheStore just because I don’t know Ruby enough (namespaces and all
that). I can’t seem to make memcache work for my session, though. I have
set your code in environments/development.rb (want to test if before
moving to production).

You can always test production with

ruby script/server webrick -e production

I keep getting errors about user class/module not
found. Any ideas why?

Can you post your exact errors?

Thanks,

Adrian M.

Jonathan


#5

Jonathan,

Thanks for the info. I had a longer reimplementation of the MemCacheStore
just because I don’t know Ruby enough (namespaces and all that). I can’t
seem to make memcache work for my session, though. I have set your code in
environments/development.rb (want to test if before moving to production). I
keep getting errors about user class/module not found. Any ideas why?

Thanks,

Here’s what my environment.rb looks like (based off of Jonathan’s blog
entry). Hope it helps.

MemCache

require ‘memcache’
require ‘memcache_util’

MEMCACHE_SERVERS = ‘127.0.0.1:11211’ unless defined?(MEMCACHE_SERVERS)

CACHE = MemCache.new :c_threshold => 10_000,
:compression => false,
:debug => false,
:namespace => “#{RAILS_ENV}”,
:readonly => false,
:urlencode => false
CACHE.servers = MEMCACHE_SERVERS

Use our memcache object to store sessions

ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update(
:database_manager => CGI::Session::MemCacheStore,
:cache => CACHE
)


#6

Philip,

Thanks for the info. Question, are you doing that before or after the
whole
“Rails::Initializer.run do |config|” code?

Thanks,

Adrian M.


#7

Thanks for the info. Question, are you doing that before or after the whole
“Rails::Initializer.run do |config|” code?

After. The rest of my environment.rb file is stock.


#8

do you have

class ApplicationController < ActionController::Base
model :user
end

In the application controller?

Jonathan


#9

Jonathan,

I don’t and for some reason I can quite remember I thought it wasn’t
needed
anymore. The funny thing is that if I switch to PStore (session_type =
“pstore”) then I don’t have any problems with classes not loaded. I
will
try adding that although there are a lot of models that I save in the
session depending of what the suer does on the site. Do you kow if there
is
something in the PStore manager that loads on demmand the classes the
current session requires?

Thanks,

Adrian M.


#10

Here is the error log after I login. BTW, I’m keeping the user in the
session and not just the user id:

Processing LoginController#login (for 123.456.789.123 at 2006-04-21
17:37:42) [POST]
Session ID: d6e08ee536af1abb395dbb183820fa11
Parameters: {“user”=>{“username”=>“admin”, “password”=>“xxxxxx”},
“x”=>“53”, “y”=>“11”, “action”=>“login”, “controller”=>“login”}
User Columns (0.000223) SHOW FIELDS FROM users
User Load (0.000320) SELECT * FROM users WHERE (username = ‘admin’
and
password = ‘xxxxxx’) LIMIT 1
Event Columns (0.000179) SHOW FIELDS FROM events
SQL (0.000060) BEGIN
SQL (0.000266) INSERT INTO events (created_on, name, row_id,
action, description, auth_id, created) VALUES(‘2006-04-21
17:37:42’,
‘users’, 1, ‘login’, ‘123.456.789.123’, 9999,
‘2006-04-21T17:37:42-0500’)
SQL (0.000042) COMMIT
Succesful login, adding user to session
Region Load (0.000281) SELECT * FROM regions WHERE (regions.id = 13)
LIMIT 1
UserAddress Columns (0.000232) SHOW FIELDS FROM addresses
UserAddress Load (0.000404) SELECT * FROM addresses WHERE (
addresses.row_id = 1) AND ( (addresses.type = ‘UserAddress’ ) ) LIMIT
1
Logged in User nil
Redirected to http://test.domain.com/InfoCenter
Completed in 0.03118 (32 reqs/sec) | DB: 0.00201 (6%) | 302 Found [
http://test.domain.com/]
Join Table Columns (0.000182) SHOW FIELDS FROM groups_users
Group Load (0.000599) SELECT * FROM groups INNER JOIN groups_users
ON
groups.id = groups_users.group_id WHERE (groups_users.user_id = 1 )
ORDER BY
name
Group Columns (0.000129) SHOW FIELDS FROM groups
Region Columns (0.000143) SHOW FIELDS FROM regions
Preference Load (0.000457) SELECT * FROM preferences WHERE (
preferences.user_id = 1) ORDER BY group, name
Preference Columns (0.000159) SHOW FIELDS FROM preferences
undefined class/module User
/usr/local/lib/ruby/gems/1.8/gems/memcache-client-1.0.3/lib/memcache.rb:128:in
get' /usr/local/lib/ruby/1.8/thread.rb:135:insynchronize’
/usr/local/lib/ruby/gems/1.8/gems/memcache-client-1.0.3/lib/memcache.rb:98:in
get' /usr/local/lib/ruby/gems/1.8/gems/memcache-client-1.0.3/lib/memcache.rb:191:in[]’
/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action_controller/session/mem_cache_store.rb:67:in
restore' /usr/local/lib/ruby/1.8/cgi/session.rb:305:in[]’
/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action_controller/cgi_process.rb:113:in
session' /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action_controller/cgi_process.rb:141:instale_session_check!’
/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action_controller/cgi_process.rb:107:in
session' /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action_controller/base.rb:887:inassign_shortcuts_without_flash’
/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action_controller/flash.rb:141:in
assign_shortcuts' /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action_controller/base.rb:375:inprocess_without_filters’
/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action_controller/filters.rb:377:in
process_without_session_management_support' /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action_controller/session_management.rb:117:inprocess’
/usr/local/lib/ruby/gems/1.8/gems/rails-1.1.2/lib/dispatcher.rb:38:in
dispatch' /usr/local/lib/ruby/gems/1.8/gems/rails-1.1.2/lib/fcgi_handler.rb:150:inprocess_request’
/usr/local/lib/ruby/gems/1.8/gems/rails-1.1.2/lib/fcgi_handler.rb:54:in
process!' /usr/local/lib/ruby/site_ruby/1.8/fcgi.rb:600:ineach_cgi’
/usr/local/lib/ruby/site_ruby/1.8/fcgi.rb:597:in each_cgi' /usr/local/lib/ruby/gems/1.8/gems/rails-1.1.2/lib/fcgi_handler.rb:53:inprocess!’
/usr/local/lib/ruby/gems/1.8/gems/rails-1.1.2/lib/fcgi_handler.rb:23:in
`process!’
/home/iflo/domains/infocenter.iflo.com/current/public/dispatch.fcgi:24

It seems to me that the session does not know about the user
class/model. If
I switch back to a PSTORE I don’t have any problems. Very weird. Here is
my
environment.rb:

Specifies gem version of Rails to use when vendor/rails is not present

RAILS_GEM_VERSION = ‘1.1.2’

Bootstrap the Rails environment, frameworks, and default configuration

require File.join(File.dirname(FILE), ‘boot’)

====================================================================================================

Memcached


MEMCACHE_SERVERS = ‘127.0.0.1:11211’ unless defined?(MEMCACHE_SERVERS)
CACHE = MemCache.new :c_threshold => 10_000,
:compression => false,
:debug => false,
:namespace => “domain”,
:readonly => false,
:urlencode => false
CACHE.servers = MEMCACHE_SERVERS

====================================================================================================

Initializer


Rails::Initializer.run do |config|
config.frameworks -= [ :action_web_service ]
end

====================================================================================================

Fragments


class ActionController::Caching::Fragments::MemCacheStore
def data=(cache)
@data = cache
end
def write(name, value, options=nil)
if name =~ %r{^Min30}
@data.set(name, value, 30.minutes)
elsif name =~ %r{^Min60}
@data.set(name, value, 60.minutes)
elsif name =~ %r{^Min90}
@data.set(name, value, 90.minutes)
else
@data.set(name, value, 120.minutes)
end
end
end
ActionController::Base.fragment_cache_store = :mem_cache_store ,{}
ActionController::Base.fragment_cache_store.data = CACHE

====================================================================================================

Session


session_type = “memcached”
session_options = Hash.new
if session_type == “pstore”
session_options[:database_manager] = CGI::Session::PStore
session_options[:prefix] = ‘dom_’
session_options[:tmpdir] = ‘/home/domain/pstore’
else
session_options[:database_manager] = CGI::Session::MemCacheStore
session_options[:cache] = CACHE
end
session_options[:session_domain] = ‘.domain.com’
session_options[:session_key] = ‘domain’
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update(session_options)

Hope this helps in figuring this out because I keep banging my head
against
it. If you see anything that could help me please let me know.

Thanks again,

Adrian M.


#11

Jonathan,

Sorry, I was giving you the wrong information. I was doing “require
/path/to/models/user” instead of “model :user”. I don’t see a major
difference but I will try it anyway and let you know.

Thanks,

Adrian M.


#12

Jonathan,

Looks like model :model_name has been deprecated because it complaints
that
the method does not exist and I can’t find it in the docs.

Sincerely,

Adrian M.


#13

Adrian M. wrote:

Jonathan,

Looks like model :model_name has been deprecated because it complaints
that the method does not exist and I can’t find it in the docs.

I use

model :user

with Rails 1.1.2 and have no problems so far.

Jonathan