Ege Ersoz
Ege Ersoz

Reputation: 6571

Most elegant way to keep track of "last active" time

I have a website where I need to be able to display on each user's profile the last time they were "active" on the site. In this case, "active" is defined by browsing content, interacting with other users and completing courses.

My plan is to have a last_active column on the Users table, which I can update with Time.now. The question is, how do I do this without hitting up the database during every single controller action? That seems... expensive. For example, I want to avoid doing this:

# In each controller
def index
  current_user.activity
end


# In the User model
def activity
  self.update_attribute(:last_active, Time.now)
end

Because then every time a user gets the content listing, I have to make a database call.

The other option would be to have an Activity table, which I update with various user actions (kind of like audits). That would allow me to store and display more relevant information about what users are doing. But that goes back to the same question: how do I update these tables without massive overhead?

Upvotes: 3

Views: 989

Answers (4)

Dan
Dan

Reputation: 173

If you're fine with async updates, you could set up a delayed resque job, deleting previous jobs.

Resque.remove_delayed_selection RecordLastUserActivity, {
   |args| args[0]['user_id'] == current_user.id 
}
Resque.enqueue_at(10.minutes.from_now, RecordLastUserActivity, 
             user_id: current_user.id, last_seen_at: Time.now)

Not sure if this will provide greater perfomance though, it will require some testing.

Upvotes: 0

Alex Teut
Alex Teut

Reputation: 844

Don't you think about redis|memcache|any_in_memory_storage for such data?

Upvotes: 0

Alessandro
Alessandro

Reputation: 11

I don't think there is a way around the overhead without restricting when you update a particular user's 'last active' attribute.

So as Charlie Egan alluded to, you have two options:

  1. Only update the 'last active' attribute when the user logs in. You'll still get a decent sense of a user's general activity on the site just by doing this.

    Or

  2. Only update the 'last active' attribute on certain activity. For example, you mentioned in your question that users can complete courses. That seems like a fairly significant 'activity', so update the 'last active' attribute. Less significant activities, like browsing content can be ignored.

Upvotes: 1

msanteler
msanteler

Reputation: 2183

It's really a rather moot question – No, there is no way to update the database without updating the database.

If you wanted to get complicated, you could try to do some client-side scripting to store that information in a session variable or a cookie, and only commit it to the db once in a while, but that seems like a lot of work for a small feature.

Maybe if you add an index to your :last_active column you make it marginally less expensive? But otherwise, I would just go for it, and try to be conservative about how often it's updated.

You could also check if Time.now > @user.last_active+10.minutes before updating to make sure that you aren't constantly writing to the db, but then your just querying instead which may not be better...

Upvotes: 2

Related Questions