Mercurial > public > sg101
diff gpp/antispam/rate_limit.py @ 479:32cec6cd8808
Refactor RateLimiter so that if Redis is not running, everything still runs normally (minus the rate limiting protection). My assumption that creating a Redis connection would throw an exception if Redis wasn't running was wrong. The exceptions actually occur when you issue a command. This is for #224.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Sun, 25 Sep 2011 00:49:05 +0000 |
parents | 5e826e232932 |
children | 6f5fff924877 |
line wrap: on
line diff
--- a/gpp/antispam/rate_limit.py Sun Sep 11 19:50:59 2011 +0000 +++ b/gpp/antispam/rate_limit.py Sun Sep 25 00:49:05 2011 +0000 @@ -17,6 +17,9 @@ DB = getattr(settings, 'RATE_LIMIT_REDIS_DB', 0) +# This exception is thrown upon any Redis error. This insulates client code from +# knowing that we are using Redis and will allow us to use something else in the +# future. class RateLimiterUnavailable(Exception): pass @@ -62,7 +65,12 @@ key = _make_key(ip) conn = _get_connection() - conn.setex(key, count, _to_seconds(interval)) + try: + conn.setex(key, count, _to_seconds(interval)) + except redis.RedisError, e: + logger.error("rate limit (block_ip): %s" % e) + raise RateLimiterUnavailable + logger.info("Rate limiter blocked IP %s; %d / %s", ip, count, interval) @@ -84,7 +92,12 @@ Return True if the IP is blocked, and false otherwise. """ - val = self.conn.get(self.key) + try: + val = self.conn.get(self.key) + except redis.RedisError, e: + logger.error("RateLimiter (is_blocked): %s" % e) + raise RateLimiterUnavailable + try: val = int(val) if val else 0 except ValueError: @@ -105,19 +118,23 @@ parameter. """ - val = self.conn.incr(self.key) + try: + val = self.conn.incr(self.key) - # Set expire time, if necessary. - # If this is the first time, set it according to interval. - # If the set_point has just been exceeded, set it according to lockout. - if val == 1: - self.conn.expire(self.key, _to_seconds(self.interval)) - elif val == self.set_point: - self.conn.expire(self.key, _to_seconds(self.lockout)) + # Set expire time, if necessary. + # If this is the first time, set it according to interval. + # If the set_point has just been exceeded, set it according to lockout. + if val == 1: + self.conn.expire(self.key, _to_seconds(self.interval)) + elif val == self.set_point: + self.conn.expire(self.key, _to_seconds(self.lockout)) - tripped = val >= self.set_point + tripped = val >= self.set_point - if tripped: - logger.info("Rate limiter tripped for %s; counter = %d", self.ip, val) + if tripped: + logger.info("Rate limiter tripped for %s; counter = %d", self.ip, val) + return tripped - return tripped + except redis.RedisError, e: + logger.error("RateLimiter (incr): %s" % e) + raise RateLimiterUnavailable