Best Practice: Automatic session timeout/cleanup?

I'm developing an application where I need to have all sessions that
have been inactive for X minutes (in this case, I'm thinking 10
minutes, but I'm flexible to a point) automatically purged from the
database (using ActiveRecord session store).

What I've done is created a simple rake task that just looks at the
updated_at column and deletes anything older than 10 minutes. I plan
to have a cron task run this job every 10 minutes. In theory, this
should keep inactive sessions to a minimum and clean up my database
sessions at the same time automatically, keeping the number in the
table at any given time fairly low.

However, I'm concerned that running a rake task every 10 minutes
could have some performance issues. Does anybody have any feedback on
this? Is this generally considered "OK" or is there a better way
(that also can purge old sessions automatically)?

What is your motivation for removing these rows at all? Generally, large database tables that are properly indexed shouldn’t pose much of a performance concern.

This is something I've been looking into (but not implemented) and
the problem with this approach seems to be the startup overhead of
loading your Rails environment over and over.

So you might want to look at the various daemon options, i.e. just
run something continuously to periodically expunge old sessions.

FWIW,

Well, what you are both looking at doing is:

Session.delete_all, :conditions => ['updated_at < ?', 10.minutes.ago]

That translates into a pretty quick database query, depending on the number of sessions you anticipate having. WDYT?

Right, finding old sessions isn't the hard part :slight_smile:

The question is rake via cron/equiv versus background task.

Speaking only for myself, I'd need to run this much more often, say
every 2 or 3 minutes, and do related cleanup tasks as part of session
removal, meaning this would require most of the Rails environment.

What is your motivation for removing these rows at all? Generally, large
database tables that are properly indexed shouldn't pose much of a
performance concern.

The reasoning behind this is that I want old sessions that are
inactive for 10 minutes to be terminated automagically. It's a
"security" concern (notice the quotes - intentional :slight_smile: ). This is a
workplace-only application for our employees to use. Theoretically,
there's no reason that a user's session, that has been idle for 10+
minutes, should have access without logging in again. This will be
seen by customers in our retail stores, and I don't necessarily want
all this data just "available" in the event one of our sales
associates walks away from a computer, and a customer starts poking
around for no good reason. Obviously that's not "great" security, but
it's "Good Enough(TM)".

Company-wide we only have roughly ~350 employees, so the size of the
DB has never been a major concern for me. I was more curious about
the implications of, as Hassan pointed out, loading the Rails
environment every 10 minutes. I was actually thinking more along the
lines of memory leaks (even a very small one could snowball very fast
on a 10-minute cron job), but Hassan's point is more...to the point.

This is something I've been looking into (but not implemented) and
the problem with this approach seems to be the startup overhead of
loading your Rails environment over and over.

So you might want to look at the various daemon options, i.e. just
run something continuously to periodically expunge old sessions.

Thanks. This is exactly the kind of stuff I was worried about, and I
appreciate you bringing up a point I was probably just too tired to
see :slight_smile: Do you have any thoughts/ideas on a daemonized version that I
could run as a rake task? I've never written a real daemon before -
in any language - so I'm not sure even where to start. Are there any
gems that would be useful in the process?

Well, what you are both looking at doing is:

Session.delete_all, :conditions => ['updated_at < ?', 10.minutes.ago]

That translates into a pretty quick database query, depending on the
number of sessions you anticipate having. WDYT?

Yep, that's essentially what my rake task does right now. It's just
that the cost of loading the Rails environment once every 10 minutes
(as a cron job would do) would be a bit too costly, as Hassan points
out. A daemonized version of that is probably the way to go.

Thank you all for your help :slight_smile:

Hello--

What is your motivation for removing these rows at all? Generally, large
database tables that are properly indexed shouldn't pose much of a
performance concern.

The reasoning behind this is that I want old sessions that are
inactive for 10 minutes to be terminated automagically. It's a
"security" concern (notice the quotes - intentional :slight_smile: ). This is a
workplace-only application for our employees to use. Theoretically,
there's no reason that a user's session, that has been idle for 10+
minutes, should have access without logging in again. This will be
seen by customers in our retail stores, and I don't necessarily want
all this data just "available" in the event one of our sales
associates walks away from a computer, and a customer starts poking
around for no good reason. Obviously that's not "great" security, but
it's "Good Enough(TM)".

Company-wide we only have roughly ~350 employees, so the size of the
DB has never been a major concern for me. I was more curious about
the implications of, as Hassan pointed out, loading the Rails
environment every 10 minutes. I was actually thinking more along the
lines of memory leaks (even a very small one could snowball very fast
on a 10-minute cron job), but Hassan's point is more...to the point.

This is something I've been looking into (but not implemented) and
the problem with this approach seems to be the startup overhead of
loading your Rails environment over and over.

So you might want to look at the various daemon options, i.e. just
run something continuously to periodically expunge old sessions.

Thanks. This is exactly the kind of stuff I was worried about, and I
appreciate you bringing up a point I was probably just too tired to
see :slight_smile: Do you have any thoughts/ideas on a daemonized version that I
could run as a rake task? I've never written a real daemon before -
in any language - so I'm not sure even where to start. Are there any
gems that would be useful in the process?

Well, what you are both looking at doing is:

Session.delete_all, :conditions => ['updated_at < ?', 10.minutes.ago]

That translates into a pretty quick database query, depending on the
number of sessions you anticipate having. WDYT?

Yep, that's essentially what my rake task does right now. It's just
that the cost of loading the Rails environment once every 10 minutes
(as a cron job would do) would be a bit too costly, as Hassan points
out. A daemonized version of that is probably the way to go.

Thank you all for your help :slight_smile:

I'm developing an application where I need to have all sessions that
have been inactive for X minutes (in this case, I'm thinking 10
minutes, but I'm flexible to a point) automatically purged from the
database (using ActiveRecord session store).

However, I'm concerned that running a rake task every 10 minutes
could have some performance issues.

This is something I've been looking into (but not implemented) and
the problem with this approach seems to be the startup overhead of
loading your Rails environment over and over.

So you might want to look at the various daemon options, i.e. just
run something continuously to periodically expunge old sessions.

FWIW,
--

Well, what you are both looking at doing is:

Session.delete_all, :conditions => ['updated_at < ?', 10.minutes.ago]

That translates into a pretty quick database query, depending on the
number of sessions you anticipate having. WDYT?- Hide quoted text -

Out of curiosity, is there a reason the cookie-based sessions would not work for you? These auto-clean and don't clutter up your database. For your security timeout, I'd suggest something like this:

# application.rb (or application_controller.rb if it's a new rails app)

   around_filter :check_auto_logout # This needs to be run first to make sure we don't have stale expired sessions

   def check_auto_logout
     begin
       if logged_in? && current_user.is_parent? && session[:session_expiry] && session[:session_expiry] < Time.now
         session[:user_id] = nil # could remove a database row, if need be
       end
     rescue ActiveRecord::RecordNotFound # Handle stale session cookie problems.
       session[:user_id] = nil
     end

     yield

     session[:session_expiry] = Rails.env.development? ? 1.hour.since : 5.minutes.since
   end

Out of curiosity, is there a reason the cookie-based sessions would
not work for you? These auto-clean and don't clutter up your database.
For your security timeout, I'd suggest something like this:

Not being the OP, this is a bit of a hijack, but... :slight_smile:

around_filter :check_auto_logout # This needs to be run first
to make sure we don't have stale expired sessions

This seems like it would fit the OP's use case, but not mine, in that
it depends on another request coming in after the session timeout
period has expired.

Would you have a suggestion on cleanup of abandoned sessions?

Here's my use case:

Web site sells unique/limited quantity items.
User puts item in cart; item is now unavailable to other users.
User abandons cart (stops interacting with site for 30 minutes)
Cart is "emptied", item is returned to inventory.

Interested in any ideas on the most Rails-ish way to handle this.

> Out of curiosity, is there a reason the cookie-based sessions would
> not work for you? These auto-clean and don't clutter up your database.
> For your security timeout, I'd suggest something like this:

Not being the OP, this is a bit of a hijack, but... :slight_smile:

> around_filter :check_auto_logout # This needs to be run first
> to make sure we don't have stale expired sessions

This seems like it would fit the OP's use case, but not mine, in that
it depends on another request coming in after the session timeout
period has expired.

Would you have a suggestion on cleanup of abandoned sessions?

Here's my use case:

Web site sells unique/limited quantity items.
User puts item in cart; item is now unavailable to other users.
User abandons cart (stops interacting with site for 30 minutes)
Cart is "emptied", item is returned to inventory.

Well presumably in your case you have to track the fact that this item
is now locked or whatever in the database. Make it so that such locks
are updated while the user keeps using the site and have a cronjob
that expires locks from users that have not been active since X.
Another possibility is to have a locked_until field, in which case you
don't need to clear out the lock at all.

Fred

Web site sells unique/limited quantity items.
User puts item in cart; item is now unavailable to other users.
User abandons cart (stops interacting with site for 30 minutes)
Cart is "emptied", item is returned to inventory.

Well presumably in your case you have to track the fact that this item
is now locked or whatever in the database. Make it so that such locks
are updated while the user keeps using the site and have a cronjob
that expires locks from users that have not been active since X.

Yeah, it's the cronjob aspect that seems extremely clunky to me,
but that could be a background task.

Another possibility is to have a locked_until field, in which case you
don't need to clear out the lock at all.

Ah, interesting approach. Since that would have to be updated on
each subsequent request by that user, what would be the DRYest
way to trigger the update?