Mercurial > public > pelican-blog
view content/Coding/010-redis-whos-online-return.rst @ 8:e29fd75628d6
Turn on disqus comments.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Sat, 01 Feb 2014 13:58:51 -0600 |
parents | 7ce6393e6d30 |
children |
line wrap: on
line source
Who's Online with Redis & Python, a slight return ################################################# :date: 2011-12-17 19:05 :tags: Redis, Python :slug: who-s-online-with-redis-python-a-slight-return :author: Brian Neal In a `previous post`_, I blogged about building a "Who's Online" feature using Redis_ and Python_ with redis-py_. I've been integrating Celery_ into my website, and I stumbled across this old code. Since I made that post, I discovered yet another cool feature in Redis: sorted sets. So here is an even better way of implementing this feature using Redis sorted sets. A sorted set in Redis is like a regular set, but each member has a numeric score. When you add a member to a sorted set, you also specify the score for that member. You can then retrieve set members if their score falls into a certain range. You can also easily remove members outside a given score range. For a "Who's Online" feature, we need a sorted set to represent the set of all users online. Whenever we see a user, we insert that user into the set along with the current time as their score. This is accomplished with the Redis zadd_ command. If the user is already in the set, zadd_ simply updates their score with the current time. To obtain the curret list of who's online, we use the zrangebyscore_ command to retrieve the list of users who's score (time) lies between, say, 15 minutes ago, until now. Periodically, we need to remove stale members from the set. This can be accomplished by using the zremrangebyscore_ command. This command will remove all members that have a score between minimum and maximum values. In this case, we can use the beginning of time for the minimum, and 15 minutes ago for the maximum. That's really it in a nutshell. This is much simpler than my previous solution which used two sets. So let's look at some code. The first problem we need to solve is how to convert a Python ``datetime`` object into a score. This can be accomplished by converting the ``datetime`` into a POSIX timestamp integer, which is the number of seconds from the UNIX epoch of January 1, 1970. .. sourcecode:: python import datetime import time def to_timestamp(dt): """ Turn the supplied datetime object into a UNIX timestamp integer. """ return int(time.mktime(dt.timetuple())) With that handy function, here are some examples of the operations described above. .. sourcecode:: python import redis # Redis set keys: USER_SET_KEY = "whos_online:users" # the period over which we collect who's online stats: MAX_AGE = datetime.timedelta(minutes=15) # obtain a connection to redis: conn = redis.StrictRedis() # add/update a user to the who's online set: username = "sally" ts = to_timestamp(datetime.datetime.now()) conn.zadd(USER_SET_KEY, ts, username) # retrieve the list of users who have been active in the last MAX_AGE minutes now = datetime.datetime.now() min = to_timestamp(now - MAX_AGE) max = to_timestamp(now) whos_online = conn.zrangebyscore(USER_SET_KEY, min, max) # e.g. whos_online = ['sally', 'harry', 'joe'] # periodically remove stale members cutoff = to_timestamp(datetime.datetime.now() - MAX_AGE) conn.zremrangebyscore(USER_SET_KEY, 0, cutoff) .. _previous post: http://deathofagremmie.com/2011/04/25/a-better-who-s-online-with-redis-python/ .. _Redis: http://redis.io/ .. _Python: http://www.python.org .. _redis-py: https://github.com/andymccurdy/redis-py .. _Celery: http://celeryproject.org .. _zadd: http://redis.io/commands/zadd .. _zrangebyscore: http://redis.io/commands/zrangebyscore .. _zremrangebyscore: http://redis.io/commands/zremrangebyscore