1 | #!/usr/bin/env python |
---|
2 | # -*- coding: utf-8 -*- |
---|
3 | """ |
---|
4 | Developed by niphlod@gmail.com |
---|
5 | License MIT/BSD/GPL |
---|
6 | |
---|
7 | Serves as base to implement Redis connection object and various utils |
---|
8 | for redis_cache, redis_session and redis_scheduler in the future |
---|
9 | Should-could be overriden in case redis doesn't keep up (e.g. cluster support) |
---|
10 | to ensure compatibility with another - similar - library |
---|
11 | """ |
---|
12 | |
---|
13 | import logging |
---|
14 | from threading import Lock |
---|
15 | import time |
---|
16 | from gluon import current |
---|
17 | |
---|
18 | logger = logging.getLogger("web2py.redis_utils") |
---|
19 | |
---|
20 | try: |
---|
21 | import redis |
---|
22 | from redis.exceptions import WatchError as RWatchError |
---|
23 | from redis.exceptions import ConnectionError as RConnectionError |
---|
24 | except ImportError: |
---|
25 | logger.error("Needs redis library to work") |
---|
26 | raise RuntimeError('Needs redis library to work') |
---|
27 | |
---|
28 | |
---|
29 | locker = Lock() |
---|
30 | |
---|
31 | |
---|
32 | def RConn(application=None, *args, **vars): |
---|
33 | """ |
---|
34 | Istantiates a StrictRedis connection with parameters, at the first time |
---|
35 | only |
---|
36 | """ |
---|
37 | locker.acquire() |
---|
38 | try: |
---|
39 | if application is None: |
---|
40 | application = current.request.application |
---|
41 | instance_name = 'redis_conn_' + application |
---|
42 | if not hasattr(RConn, instance_name): |
---|
43 | setattr(RConn, instance_name, redis.StrictRedis(*args, **vars)) |
---|
44 | return getattr(RConn, instance_name) |
---|
45 | finally: |
---|
46 | locker.release() |
---|
47 | |
---|
48 | def acquire_lock(conn, lockname, identifier, ltime=10): |
---|
49 | while True: |
---|
50 | if conn.set(lockname, identifier, ex=ltime, nx=True): |
---|
51 | return identifier |
---|
52 | time.sleep(.01) |
---|
53 | |
---|
54 | |
---|
55 | _LUA_RELEASE_LOCK = """ |
---|
56 | if redis.call("get", KEYS[1]) == ARGV[1] |
---|
57 | then |
---|
58 | return redis.call("del", KEYS[1]) |
---|
59 | else |
---|
60 | return 0 |
---|
61 | end |
---|
62 | """ |
---|
63 | |
---|
64 | |
---|
65 | def release_lock(instance, lockname, identifier): |
---|
66 | return instance._release_script( |
---|
67 | keys=[lockname], args=[identifier]) |
---|
68 | |
---|
69 | |
---|
70 | def register_release_lock(conn): |
---|
71 | rtn = conn.register_script(_LUA_RELEASE_LOCK) |
---|
72 | return rtn |
---|