Mercurial > public > pelican-blog
comparison content/Coding/010-redis-whos-online-return.rst @ 4:7ce6393e6d30
Adding converted blog posts from old blog.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Thu, 30 Jan 2014 21:45:03 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:c3115da3ff73 | 4:7ce6393e6d30 |
---|---|
1 Who's Online with Redis & Python, a slight return | |
2 ################################################# | |
3 | |
4 :date: 2011-12-17 19:05 | |
5 :tags: Redis, Python | |
6 :slug: who-s-online-with-redis-python-a-slight-return | |
7 :author: Brian Neal | |
8 | |
9 In a `previous post`_, I blogged about building a "Who's Online" feature using | |
10 Redis_ and Python_ with redis-py_. I've been integrating Celery_ into my | |
11 website, and I stumbled across this old code. Since I made that post, I | |
12 discovered yet another cool feature in Redis: sorted sets. So here is an even | |
13 better way of implementing this feature using Redis sorted sets. | |
14 | |
15 A sorted set in Redis is like a regular set, but each member has a numeric | |
16 score. When you add a member to a sorted set, you also specify the score for | |
17 that member. You can then retrieve set members if their score falls into a | |
18 certain range. You can also easily remove members outside a given score range. | |
19 | |
20 For a "Who's Online" feature, we need a sorted set to represent the set | |
21 of all users online. Whenever we see a user, we insert that user into the set | |
22 along with the current time as their score. This is accomplished with the Redis | |
23 zadd_ command. If the user is already in the set, zadd_ simply updates | |
24 their score with the current time. | |
25 | |
26 To obtain the curret list of who's online, we use the zrangebyscore_ command to | |
27 retrieve the list of users who's score (time) lies between, say, 15 minutes ago, | |
28 until now. | |
29 | |
30 Periodically, we need to remove stale members from the set. This can be | |
31 accomplished by using the zremrangebyscore_ command. This command will remove | |
32 all members that have a score between minimum and maximum values. In this case, | |
33 we can use the beginning of time for the minimum, and 15 minutes ago for the | |
34 maximum. | |
35 | |
36 That's really it in a nutshell. This is much simpler than my previous | |
37 solution which used two sets. | |
38 | |
39 So let's look at some code. The first problem we need to solve is how to | |
40 convert a Python ``datetime`` object into a score. This can be accomplished by | |
41 converting the ``datetime`` into a POSIX timestamp integer, which is the number | |
42 of seconds from the UNIX epoch of January 1, 1970. | |
43 | |
44 .. sourcecode:: python | |
45 | |
46 import datetime | |
47 import time | |
48 | |
49 def to_timestamp(dt): | |
50 """ | |
51 Turn the supplied datetime object into a UNIX timestamp integer. | |
52 | |
53 """ | |
54 return int(time.mktime(dt.timetuple())) | |
55 | |
56 With that handy function, here are some examples of the operations described | |
57 above. | |
58 | |
59 .. sourcecode:: python | |
60 | |
61 import redis | |
62 | |
63 # Redis set keys: | |
64 USER_SET_KEY = "whos_online:users" | |
65 | |
66 # the period over which we collect who's online stats: | |
67 MAX_AGE = datetime.timedelta(minutes=15) | |
68 | |
69 # obtain a connection to redis: | |
70 conn = redis.StrictRedis() | |
71 | |
72 # add/update a user to the who's online set: | |
73 | |
74 username = "sally" | |
75 ts = to_timestamp(datetime.datetime.now()) | |
76 conn.zadd(USER_SET_KEY, ts, username) | |
77 | |
78 # retrieve the list of users who have been active in the last MAX_AGE minutes | |
79 | |
80 now = datetime.datetime.now() | |
81 min = to_timestamp(now - MAX_AGE) | |
82 max = to_timestamp(now) | |
83 | |
84 whos_online = conn.zrangebyscore(USER_SET_KEY, min, max) | |
85 | |
86 # e.g. whos_online = ['sally', 'harry', 'joe'] | |
87 | |
88 # periodically remove stale members | |
89 | |
90 cutoff = to_timestamp(datetime.datetime.now() - MAX_AGE) | |
91 conn.zremrangebyscore(USER_SET_KEY, 0, cutoff) | |
92 | |
93 .. _previous post: http://deathofagremmie.com/2011/04/25/a-better-who-s-online-with-redis-python/ | |
94 .. _Redis: http://redis.io/ | |
95 .. _Python: http://www.python.org | |
96 .. _redis-py: https://github.com/andymccurdy/redis-py | |
97 .. _Celery: http://celeryproject.org | |
98 .. _zadd: http://redis.io/commands/zadd | |
99 .. _zrangebyscore: http://redis.io/commands/zrangebyscore | |
100 .. _zremrangebyscore: http://redis.io/commands/zremrangebyscore |