Skip to content

Commit 3946da2

Browse files
authored
redisjson support (#1636)
1 parent 0ef4c07 commit 3946da2

29 files changed

+855
-244
lines changed

docker-compose.yml

Lines changed: 0 additions & 58 deletions
This file was deleted.

docker/base/Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
FROM redis:6.2.5-buster
1+
FROM redis:6.2.6-buster
2+
3+
CMD ["redis-server", "/redis.conf"]

docker/base/Dockerfile.sentinel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM redis:6.2.6-buster
2+
3+
CMD ["redis-sentinel", "/sentinel.conf"]

docker/base/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Dockers in this folder are built, and uploaded to the redisfab dockerhub store.

docker/master/Dockerfile

Lines changed: 0 additions & 7 deletions
This file was deleted.

docker/master/redis.conf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
bind master 127.0.0.1
21
port 6379
32
save ""

docker/replica/Dockerfile

Lines changed: 0 additions & 7 deletions
This file was deleted.

docker/replica/redis.conf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
bind replica 127.0.0.1
21
port 6380
32
save ""
43
replicaof master 6379

docker/sentinel_1/Dockerfile

Lines changed: 0 additions & 7 deletions
This file was deleted.

docker/sentinel_1/sentinel.conf

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
bind sentinel_1 127.0.0.1
21
port 26379
32

4-
sentinel monitor redis-py-test master 6379 2
3+
sentinel monitor redis-py-test 127.0.0.1 6379 2
54
sentinel down-after-milliseconds redis-py-test 5000
65
sentinel failover-timeout redis-py-test 60000
76
sentinel parallel-syncs redis-py-test 1

docker/sentinel_2/Dockerfile

Lines changed: 0 additions & 7 deletions
This file was deleted.

docker/sentinel_2/sentinel.conf

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
bind sentinel_2 127.0.0.1
21
port 26380
32

4-
sentinel monitor redis-py-test master 6379 2
3+
sentinel monitor redis-py-test 127.0.0.1 6379 2
54
sentinel down-after-milliseconds redis-py-test 5000
65
sentinel failover-timeout redis-py-test 60000
76
sentinel parallel-syncs redis-py-test 1

docker/sentinel_3/Dockerfile

Lines changed: 0 additions & 7 deletions
This file was deleted.

docker/sentinel_3/sentinel.conf

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
bind sentinel_3 127.0.0.1
21
port 26381
32

4-
sentinel monitor redis-py-test master 6379 2
3+
sentinel monitor redis-py-test 127.0.0.1 6379 2
54
sentinel down-after-milliseconds redis-py-test 5000
65
sentinel failover-timeout redis-py-test 60000
76
sentinel parallel-syncs redis-py-test 1

redis/client.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
import threading
77
import time
88
import warnings
9-
from redis.commands import (
10-
list_or_args,
11-
Commands
12-
)
9+
from redis.commands import CoreCommands, RedisModuleCommands, list_or_args
1310
from redis.connection import (ConnectionPool, UnixDomainSocketConnection,
1411
SSLConnection)
1512
from redis.lock import Lock
@@ -609,7 +606,7 @@ def parse_set_result(response, **options):
609606
return response and str_if_bytes(response) == 'OK'
610607

611608

612-
class Redis(Commands, object):
609+
class Redis(RedisModuleCommands, CoreCommands, object):
613610
"""
614611
Implementation of the Redis protocol.
615612
@@ -898,6 +895,47 @@ def set_response_callback(self, command, callback):
898895
"Set a custom Response Callback"
899896
self.response_callbacks[command] = callback
900897

898+
def load_external_module(self, modname, funcname, func):
899+
"""
900+
This function can be used to add externally defined redis modules,
901+
and their namespaces to the redis client.
902+
modname - A string containing the name of the redis module to look for
903+
in the redis info block.
904+
funcname - A string containing the name of the function to create
905+
func - The function, being added to this class.
906+
907+
ex: Assume that one has a custom redis module named foomod that
908+
creates command named 'foo.dothing' and 'foo.anotherthing' in redis.
909+
To load function functions into this namespace:
910+
911+
from redis import Redis
912+
from foomodule import F
913+
r = Redis()
914+
r.load_external_module("foomod", "foo", F)
915+
r.foo().dothing('your', 'arguments')
916+
917+
For a concrete example see the reimport of the redisjson module in
918+
tests/test_connection.py::test_loading_external_modules
919+
"""
920+
mods = self.loaded_modules
921+
if modname.lower() not in mods:
922+
raise ModuleError("{} is not loaded in redis.".format(modname))
923+
setattr(self, funcname, func)
924+
925+
@property
926+
def loaded_modules(self):
927+
key = '__redis_modules__'
928+
mods = getattr(self, key, None)
929+
if mods is not None:
930+
return mods
931+
932+
try:
933+
mods = [f.get('name').lower() for f in self.info().get('modules')]
934+
except TypeError:
935+
mods = []
936+
setattr(self, key, mods)
937+
return mods
938+
901939
def pipeline(self, transaction=True, shard_hint=None):
902940
"""
903941
Return a new pipeline object that can queue multiple commands for

redis/commands/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from .core import CoreCommands
2+
from .redismodules import RedisModuleCommands
3+
from .helpers import list_or_args
4+
from .sentinel import SentinelCommands
5+
6+
__all__ = [
7+
'CoreCommands',
8+
'RedisModuleCommands',
9+
'SentinelCommands',
10+
'list_or_args'
11+
]

redis/commands.py renamed to redis/commands/core.py

Lines changed: 6 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import warnings
44
import hashlib
55

6+
from .helpers import list_or_args
67
from redis.exceptions import (
78
ConnectionError,
89
DataError,
@@ -11,24 +12,7 @@
1112
)
1213

1314

14-
def list_or_args(keys, args):
15-
# returns a single new list combining keys and args
16-
try:
17-
iter(keys)
18-
# a string or bytes instance can be iterated, but indicates
19-
# keys wasn't passed as a list
20-
if isinstance(keys, (bytes, str)):
21-
keys = [keys]
22-
else:
23-
keys = list(keys)
24-
except TypeError:
25-
keys = [keys]
26-
if args:
27-
keys.extend(args)
28-
return keys
29-
30-
31-
class Commands:
15+
class CoreCommands:
3216
"""
3317
A class containing all of the implemented redis commands. This class is
3418
to be used as a mixin.
@@ -1173,16 +1157,16 @@ def set(self, name, value,
11731157
if ex is not None:
11741158
pieces.append('EX')
11751159
if isinstance(ex, datetime.timedelta):
1176-
ex = int(ex.total_seconds())
1177-
if isinstance(ex, int):
1160+
pieces.append(int(ex.total_seconds()))
1161+
elif isinstance(ex, int):
11781162
pieces.append(ex)
11791163
else:
11801164
raise DataError("ex must be datetime.timedelta or int")
11811165
if px is not None:
11821166
pieces.append('PX')
11831167
if isinstance(px, datetime.timedelta):
1184-
px = int(px.total_seconds() * 1000)
1185-
if isinstance(px, int):
1168+
pieces.append(int(px.total_seconds() * 1000))
1169+
elif isinstance(px, int):
11861170
pieces.append(px)
11871171
else:
11881172
raise DataError("px must be datetime.timedelta or int")
@@ -3413,99 +3397,3 @@ def execute(self):
34133397
command = self.command
34143398
self.reset()
34153399
return self.client.execute_command(*command)
3416-
3417-
3418-
class SentinelCommands:
3419-
"""
3420-
A class containing the commands specific to redis sentinal. This class is
3421-
to be used as a mixin.
3422-
"""
3423-
3424-
def sentinel(self, *args):
3425-
"Redis Sentinel's SENTINEL command."
3426-
warnings.warn(
3427-
DeprecationWarning('Use the individual sentinel_* methods'))
3428-
3429-
def sentinel_get_master_addr_by_name(self, service_name):
3430-
"Returns a (host, port) pair for the given ``service_name``"
3431-
return self.execute_command('SENTINEL GET-MASTER-ADDR-BY-NAME',
3432-
service_name)
3433-
3434-
def sentinel_master(self, service_name):
3435-
"Returns a dictionary containing the specified masters state."
3436-
return self.execute_command('SENTINEL MASTER', service_name)
3437-
3438-
def sentinel_masters(self):
3439-
"Returns a list of dictionaries containing each master's state."
3440-
return self.execute_command('SENTINEL MASTERS')
3441-
3442-
def sentinel_monitor(self, name, ip, port, quorum):
3443-
"Add a new master to Sentinel to be monitored"
3444-
return self.execute_command('SENTINEL MONITOR', name, ip, port, quorum)
3445-
3446-
def sentinel_remove(self, name):
3447-
"Remove a master from Sentinel's monitoring"
3448-
return self.execute_command('SENTINEL REMOVE', name)
3449-
3450-
def sentinel_sentinels(self, service_name):
3451-
"Returns a list of sentinels for ``service_name``"
3452-
return self.execute_command('SENTINEL SENTINELS', service_name)
3453-
3454-
def sentinel_set(self, name, option, value):
3455-
"Set Sentinel monitoring parameters for a given master"
3456-
return self.execute_command('SENTINEL SET', name, option, value)
3457-
3458-
def sentinel_slaves(self, service_name):
3459-
"Returns a list of slaves for ``service_name``"
3460-
return self.execute_command('SENTINEL SLAVES', service_name)
3461-
3462-
def sentinel_reset(self, pattern):
3463-
"""
3464-
This command will reset all the masters with matching name.
3465-
The pattern argument is a glob-style pattern.
3466-
3467-
The reset process clears any previous state in a master (including a
3468-
failover in progress), and removes every slave and sentinel already
3469-
discovered and associated with the master.
3470-
"""
3471-
return self.execute_command('SENTINEL RESET', pattern, once=True)
3472-
3473-
def sentinel_failover(self, new_master_name):
3474-
"""
3475-
Force a failover as if the master was not reachable, and without
3476-
asking for agreement to other Sentinels (however a new version of the
3477-
configuration will be published so that the other Sentinels will
3478-
update their configurations).
3479-
"""
3480-
return self.execute_command('SENTINEL FAILOVER', new_master_name)
3481-
3482-
def sentinel_ckquorum(self, new_master_name):
3483-
"""
3484-
Check if the current Sentinel configuration is able to reach the
3485-
quorum needed to failover a master, and the majority needed to
3486-
authorize the failover.
3487-
3488-
This command should be used in monitoring systems to check if a
3489-
Sentinel deployment is ok.
3490-
"""
3491-
return self.execute_command('SENTINEL CKQUORUM',
3492-
new_master_name,
3493-
once=True)
3494-
3495-
def sentinel_flushconfig(self):
3496-
"""
3497-
Force Sentinel to rewrite its configuration on disk, including the
3498-
current Sentinel state.
3499-
3500-
Normally Sentinel rewrites the configuration every time something
3501-
changes in its state (in the context of the subset of the state which
3502-
is persisted on disk across restart).
3503-
However sometimes it is possible that the configuration file is lost
3504-
because of operation errors, disk failures, package upgrade scripts or
3505-
configuration managers. In those cases a way to to force Sentinel to
3506-
rewrite the configuration file is handy.
3507-
3508-
This command works even if the previous configuration file is
3509-
completely missing.
3510-
"""
3511-
return self.execute_command('SENTINEL FLUSHCONFIG')

0 commit comments

Comments
 (0)