Skip to content

Commit e21085d

Browse files
authored
Merge branch 'master' into alter-expire
2 parents 0e1389c + c5d19b8 commit e21085d

File tree

15 files changed

+299
-89
lines changed

15 files changed

+299
-89
lines changed

CHANGES

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
* Create codeql-analysis.yml (#1988). Thanks @chayim
1+
* Create codeql-analysis.yml (#1988). Thanks @chayim
2+
* Add limited support for Lua scripting with RedisCluster
3+
* Implement `.lock()` method on RedisCluster
24
* 4.1.3 (Feb 8, 2022)
3-
* Fix flushdb and flushall (#1926)
4-
* Add redis5 and redis4 dockers (#1871)
5-
* Change json.clear test multi to be up to date with redisjson (#1922)
6-
* Fixing volume for unstable_cluster docker (#1914)
7-
* Update changes file with changes since 4.0.0-beta2 (#1915)
5+
* Fix flushdb and flushall (#1926)
6+
* Add redis5 and redis4 dockers (#1871)
7+
* Change json.clear test multi to be up to date with redisjson (#1922)
8+
* Fixing volume for unstable_cluster docker (#1914)
9+
* Update changes file with changes since 4.0.0-beta2 (#1915)
810
* 4.1.2 (Jan 27, 2022)
911
* Invalid OCSP certificates should raise ConnectionError on failed validation (#1907)
1012
* Added retry mechanism on socket timeouts when connecting to the server (#1895)
@@ -94,10 +96,10 @@
9496
* Removing command on initial connections (#1722)
9597
* Removing hiredis warning when not installed (#1721)
9698
* 4.0.0 (Nov 15, 2021)
97-
* FT.EXPLAINCLI intentionally raising NotImplementedError
99+
* FT.EXPLAINCLI intentionally raising NotImplementedError
98100
* Restoring ZRANGE desc for Redis < 6.2.0 (#1697)
99101
* Response parsing occasionally fails to parse floats (#1692)
100-
* Re-enabling read-the-docs (#1707)
102+
* Re-enabling read-the-docs (#1707)
101103
* Call HSET after FT.CREATE to avoid keyspace scan (#1706)
102104
* Unit tests fixes for compatibility (#1703)
103105
* Improve documentation about Locks (#1701)
@@ -117,7 +119,7 @@
117119
* Sleep for flaky search test (#1680)
118120
* Test function renames, to match standards (#1679)
119121
* Docstring improvements for Redis class (#1675)
120-
* Fix georadius tests (#1672)
122+
* Fix georadius tests (#1672)
121123
* Improvements to JSON coverage (#1666)
122124
* Add python_requires setuptools check for python > 3.6 (#1656)
123125
* SMISMEMBER support (#1667)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# produces redisfab/redis-py-modcluster:6.2.6
2+
FROM redislabs/redismod:edge
3+
4+
COPY create_redismod_cluster.sh /create_redismod_cluster.sh
5+
RUN chmod +x /create_redismod_cluster.sh
6+
7+
EXPOSE 46379 46380 46381 46382 46383 46384
8+
9+
ENV START_PORT=46379
10+
ENV END_PORT=46384
11+
ENTRYPOINT []
12+
CMD /create_redismod_cluster.sh
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#! /bin/bash
2+
3+
mkdir -p /nodes
4+
touch /nodes/nodemap
5+
if [ -z ${START_PORT} ]; then
6+
START_PORT=46379
7+
fi
8+
if [ -z ${END_PORT} ]; then
9+
END_PORT=46384
10+
fi
11+
if [ ! -z "$3" ]; then
12+
START_PORT=$2
13+
START_PORT=$3
14+
fi
15+
echo "STARTING: ${START_PORT}"
16+
echo "ENDING: ${END_PORT}"
17+
18+
for PORT in `seq ${START_PORT} ${END_PORT}`; do
19+
mkdir -p /nodes/$PORT
20+
if [[ -e /redis.conf ]]; then
21+
cp /redis.conf /nodes/$PORT/redis.conf
22+
else
23+
touch /nodes/$PORT/redis.conf
24+
fi
25+
cat << EOF >> /nodes/$PORT/redis.conf
26+
port ${PORT}
27+
cluster-enabled yes
28+
daemonize yes
29+
logfile /redis.log
30+
dir /nodes/$PORT
31+
EOF
32+
33+
set -x
34+
redis-server /nodes/$PORT/redis.conf
35+
if [ $? -ne 0 ]; then
36+
echo "Redis failed to start, exiting."
37+
continue
38+
fi
39+
echo 127.0.0.1:$PORT >> /nodes/nodemap
40+
done
41+
if [ -z "${REDIS_PASSWORD}" ]; then
42+
echo yes | redis-cli --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1
43+
else
44+
echo yes | redis-cli -a ${REDIS_PASSWORD} --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1
45+
fi
46+
tail -f /redis.log

docker/redismod_cluster/redis.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
loadmodule /usr/lib/redis/modules/redisai.so
2+
loadmodule /usr/lib/redis/modules/redisearch.so
3+
loadmodule /usr/lib/redis/modules/redisgraph.so
4+
loadmodule /usr/lib/redis/modules/redistimeseries.so
5+
loadmodule /usr/lib/redis/modules/rejson.so
6+
loadmodule /usr/lib/redis/modules/redisbloom.so
7+
loadmodule /var/opt/redislabs/lib/modules/redisgears.so Plugin /var/opt/redislabs/modules/rg/plugin/gears_python.so Plugin /var/opt/redislabs/modules/rg/plugin/gears_jvm.so JvmOptions -Djava.class.path=/var/opt/redislabs/modules/rg/gear_runtime-jar-with-dependencies.jar JvmPath /var/opt/redislabs/modules/rg/OpenJDK/jdk-11.0.9.1+1/
8+

redis/asyncio/client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,10 @@ def lock(
348348
continue trying forever. ``blocking_timeout`` can be specified as a
349349
float or integer, both representing the number of seconds to wait.
350350
351-
``lock_class`` forces the specified lock implementation.
351+
``lock_class`` forces the specified lock implementation. Note that as
352+
of redis-py 3.0, the only lock class we implement is ``Lock`` (which is
353+
a Lua-based lock). So, it's unlikely you'll need this parameter, unless
354+
you have created your own custom lock class.
352355
353356
``thread_local`` indicates whether the lock token is placed in
354357
thread-local storage. By default, the token is placed in thread local

redis/asyncio/retry.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from asyncio import sleep
2-
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Tuple, TypeVar
2+
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Tuple, Type, TypeVar
33

44
from redis.exceptions import ConnectionError, RedisError, TimeoutError
55

@@ -19,7 +19,7 @@ def __init__(
1919
self,
2020
backoff: "AbstractBackoff",
2121
retries: int,
22-
supported_errors: Tuple[RedisError, ...] = (
22+
supported_errors: Tuple[Type[RedisError], ...] = (
2323
ConnectionError,
2424
TimeoutError,
2525
),

redis/client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,10 @@ def lock(
10821082
continue trying forever. ``blocking_timeout`` can be specified as a
10831083
float or integer, both representing the number of seconds to wait.
10841084
1085-
``lock_class`` forces the specified lock implementation.
1085+
``lock_class`` forces the specified lock implementation. Note that as
1086+
of redis-py 3.0, the only lock class we implement is ``Lock`` (which is
1087+
a Lua-based lock). So, it's unlikely you'll need this parameter, unless
1088+
you have created your own custom lock class.
10861089
10871090
``thread_local`` indicates whether the lock token is placed in
10881091
thread-local storage. By default, the token is placed in thread local

redis/cluster.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
TimeoutError,
2929
TryAgainError,
3030
)
31+
from redis.lock import Lock
3132
from redis.utils import (
3233
dict_merge,
3334
list_keys_to_dict,
@@ -227,6 +228,7 @@ class RedisCluster(RedisClusterCommands):
227228
"ACL SETUSER",
228229
"ACL USERS",
229230
"ACL WHOAMI",
231+
"AUTH",
230232
"CLIENT LIST",
231233
"CLIENT SETNAME",
232234
"CLIENT GETNAME",
@@ -742,6 +744,72 @@ def pipeline(self, transaction=None, shard_hint=None):
742744
reinitialize_steps=self.reinitialize_steps,
743745
)
744746

747+
def lock(
748+
self,
749+
name,
750+
timeout=None,
751+
sleep=0.1,
752+
blocking_timeout=None,
753+
lock_class=None,
754+
thread_local=True,
755+
):
756+
"""
757+
Return a new Lock object using key ``name`` that mimics
758+
the behavior of threading.Lock.
759+
760+
If specified, ``timeout`` indicates a maximum life for the lock.
761+
By default, it will remain locked until release() is called.
762+
763+
``sleep`` indicates the amount of time to sleep per loop iteration
764+
when the lock is in blocking mode and another client is currently
765+
holding the lock.
766+
767+
``blocking_timeout`` indicates the maximum amount of time in seconds to
768+
spend trying to acquire the lock. A value of ``None`` indicates
769+
continue trying forever. ``blocking_timeout`` can be specified as a
770+
float or integer, both representing the number of seconds to wait.
771+
772+
``lock_class`` forces the specified lock implementation. Note that as
773+
of redis-py 3.0, the only lock class we implement is ``Lock`` (which is
774+
a Lua-based lock). So, it's unlikely you'll need this parameter, unless
775+
you have created your own custom lock class.
776+
777+
``thread_local`` indicates whether the lock token is placed in
778+
thread-local storage. By default, the token is placed in thread local
779+
storage so that a thread only sees its token, not a token set by
780+
another thread. Consider the following timeline:
781+
782+
time: 0, thread-1 acquires `my-lock`, with a timeout of 5 seconds.
783+
thread-1 sets the token to "abc"
784+
time: 1, thread-2 blocks trying to acquire `my-lock` using the
785+
Lock instance.
786+
time: 5, thread-1 has not yet completed. redis expires the lock
787+
key.
788+
time: 5, thread-2 acquired `my-lock` now that it's available.
789+
thread-2 sets the token to "xyz"
790+
time: 6, thread-1 finishes its work and calls release(). if the
791+
token is *not* stored in thread local storage, then
792+
thread-1 would see the token value as "xyz" and would be
793+
able to successfully release the thread-2's lock.
794+
795+
In some use cases it's necessary to disable thread local storage. For
796+
example, if you have code where one thread acquires a lock and passes
797+
that lock instance to a worker thread to release later. If thread
798+
local storage isn't disabled in this case, the worker thread won't see
799+
the token set by the thread that acquired the lock. Our assumption
800+
is that these cases aren't common and as such default to using
801+
thread local storage."""
802+
if lock_class is None:
803+
lock_class = Lock
804+
return lock_class(
805+
self,
806+
name,
807+
timeout=timeout,
808+
sleep=sleep,
809+
blocking_timeout=blocking_timeout,
810+
thread_local=thread_local,
811+
)
812+
745813
def _determine_nodes(self, *args, **kwargs):
746814
command = args[0]
747815
nodes_flag = kwargs.pop("nodes_flag", None)

0 commit comments

Comments
 (0)