redis-simplify 2.1.2__tar.gz → 2.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {redis_simplify-2.1.2/redis_simplify.egg-info → redis_simplify-2.1.4}/PKG-INFO +3 -2
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/README.md +2 -1
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/pyproject.toml +1 -1
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/admin.py +5 -3
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/batch.py +9 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/connection.py +1 -1
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/lock.py +13 -4
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/pubsub.py +17 -12
- {redis_simplify-2.1.2 → redis_simplify-2.1.4/redis_simplify.egg-info}/PKG-INFO +3 -2
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/tests/test_logging.py +2 -2
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/LICENSE +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/__init__.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/client.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/__init__.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/cache.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/decorator_metrics.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/decorators.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/hash.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/health.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/json.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/list.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/metrics.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/pipeline.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/ratelimit.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/set.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/sorted_set.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/string.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify/mixins/utils.py +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify.egg-info/SOURCES.txt +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify.egg-info/dependency_links.txt +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify.egg-info/requires.txt +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/redis_simplify.egg-info/top_level.txt +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/setup.cfg +0 -0
- {redis_simplify-2.1.2 → redis_simplify-2.1.4}/tests/test_client.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: redis-simplify
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.4
|
|
4
4
|
Summary: Convenience wrapper for Redis - connection, JSON helpers, and automatic reconnection
|
|
5
5
|
Author-email: Paulo Ricardo Tebet Lyrio <tebetpaulo91@yahoo.com>
|
|
6
6
|
License: MIT
|
|
@@ -383,6 +383,7 @@ DEBUG:redis_simplify.client:Get test: hello world...
|
|
|
383
383
|
| `rate_limit_check(key, max_requests, window_seconds)` | Check if action is allowed |
|
|
384
384
|
| `rate_limit_remaining(key, max_requests, window_seconds)` | Get remaining requests |
|
|
385
385
|
| `rate_limit_reset(key, window_seconds)` | Get seconds until reset |
|
|
386
|
+
| `run_with_rate_limit(operation, rate_key, max_requests, window_seconds, *args, **kwargs)` | Execute operation with automatic rate limit |
|
|
386
387
|
|
|
387
388
|
### Distributed Lock
|
|
388
389
|
| Method | Description |
|
|
@@ -433,7 +434,7 @@ DEBUG:redis_simplify.client:Get test: hello world...
|
|
|
433
434
|
| `ping()` | Verify connectivity |
|
|
434
435
|
| `pipeline()` | Create a Redis pipeline |
|
|
435
436
|
| `scan(cursor=0, match=None, count=None)` | Iterate keys using SCAN |
|
|
436
|
-
| `
|
|
437
|
+
| `flushall()` | Remove all Redis databases |
|
|
437
438
|
| `close()` | Close the connection |
|
|
438
439
|
| `set_log_level(level)` | Change log level at runtime|
|
|
439
440
|
|
|
@@ -351,6 +351,7 @@ DEBUG:redis_simplify.client:Get test: hello world...
|
|
|
351
351
|
| `rate_limit_check(key, max_requests, window_seconds)` | Check if action is allowed |
|
|
352
352
|
| `rate_limit_remaining(key, max_requests, window_seconds)` | Get remaining requests |
|
|
353
353
|
| `rate_limit_reset(key, window_seconds)` | Get seconds until reset |
|
|
354
|
+
| `run_with_rate_limit(operation, rate_key, max_requests, window_seconds, *args, **kwargs)` | Execute operation with automatic rate limit |
|
|
354
355
|
|
|
355
356
|
### Distributed Lock
|
|
356
357
|
| Method | Description |
|
|
@@ -401,7 +402,7 @@ DEBUG:redis_simplify.client:Get test: hello world...
|
|
|
401
402
|
| `ping()` | Verify connectivity |
|
|
402
403
|
| `pipeline()` | Create a Redis pipeline |
|
|
403
404
|
| `scan(cursor=0, match=None, count=None)` | Iterate keys using SCAN |
|
|
404
|
-
| `
|
|
405
|
+
| `flushall()` | Remove all Redis databases |
|
|
405
406
|
| `close()` | Close the connection |
|
|
406
407
|
| `set_log_level(level)` | Change log level at runtime|
|
|
407
408
|
|
|
@@ -17,12 +17,14 @@ class AdminMixin:
|
|
|
17
17
|
return 0, []
|
|
18
18
|
|
|
19
19
|
@recorded()
|
|
20
|
-
def
|
|
20
|
+
def flushall(self):
|
|
21
21
|
"""Limpa tudo (CUIDADO: apenas para testes!)"""
|
|
22
22
|
if not self._ensure_connection():
|
|
23
|
-
return
|
|
23
|
+
return False
|
|
24
24
|
try:
|
|
25
25
|
self.client.flushall()
|
|
26
26
|
logger.warning("Redis flushall executed!")
|
|
27
|
+
return True
|
|
27
28
|
except Exception as e:
|
|
28
|
-
logger.error(f"Error on flushall: {e}")
|
|
29
|
+
logger.error(f"Error on flushall: {e}")
|
|
30
|
+
return False
|
|
@@ -16,6 +16,9 @@ class BatchMixin:
|
|
|
16
16
|
|
|
17
17
|
try:
|
|
18
18
|
pipe = self.pipeline()
|
|
19
|
+
if pipe is None:
|
|
20
|
+
logger.error("Failed to create pipeline")
|
|
21
|
+
return [None] * len(keys)
|
|
19
22
|
for key in keys:
|
|
20
23
|
pipe.get(key)
|
|
21
24
|
return pipe.execute()
|
|
@@ -33,6 +36,9 @@ class BatchMixin:
|
|
|
33
36
|
|
|
34
37
|
try:
|
|
35
38
|
pipe = self.pipeline()
|
|
39
|
+
if pipe is None:
|
|
40
|
+
logger.error("Failed to create pipeline")
|
|
41
|
+
return False
|
|
36
42
|
for key, value in items:
|
|
37
43
|
if expire_seconds:
|
|
38
44
|
pipe.setex(key, expire_seconds, value)
|
|
@@ -54,6 +60,9 @@ class BatchMixin:
|
|
|
54
60
|
|
|
55
61
|
try:
|
|
56
62
|
pipe = self.pipeline()
|
|
63
|
+
if pipe is None:
|
|
64
|
+
logger.error("Failed to create pipeline")
|
|
65
|
+
return 0
|
|
57
66
|
for key in keys:
|
|
58
67
|
pipe.delete(key)
|
|
59
68
|
results = pipe.execute()
|
|
@@ -16,7 +16,7 @@ class ConnectionMixin:
|
|
|
16
16
|
socket_keepalive=self.socket_keepalive,
|
|
17
17
|
health_check_interval=self.health_check_interval
|
|
18
18
|
)
|
|
19
|
-
|
|
19
|
+
# Testa conexão
|
|
20
20
|
self.client.ping()
|
|
21
21
|
logger.info(f"RedisClient connected: {self.host}:{self.port}")
|
|
22
22
|
except Exception as e:
|
|
@@ -21,6 +21,7 @@ class RedisLock:
|
|
|
21
21
|
self.timeout = timeout
|
|
22
22
|
self.blocking_timeout = blocking_timeout
|
|
23
23
|
self.token = None
|
|
24
|
+
self.acquired = False
|
|
24
25
|
|
|
25
26
|
def __enter__(self):
|
|
26
27
|
self.acquire()
|
|
@@ -33,6 +34,7 @@ class RedisLock:
|
|
|
33
34
|
while True:
|
|
34
35
|
self.token = str(uuid.uuid4())
|
|
35
36
|
if self.client.set(self.name, self.token, self.timeout, nx=True):
|
|
37
|
+
self.acquired = True
|
|
36
38
|
return True
|
|
37
39
|
|
|
38
40
|
if self.blocking_timeout is None:
|
|
@@ -47,10 +49,11 @@ class RedisLock:
|
|
|
47
49
|
if exc_type:
|
|
48
50
|
logger.error(f"Error on lock: {exc_type.__name__}: {exc_val}")
|
|
49
51
|
logger.error(f"Traceback: {''.join(traceback.format_tb(exc_tb))}")
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
if not self.acquired:
|
|
53
|
+
return False
|
|
54
|
+
|
|
52
55
|
if not self.client._ensure_connection():
|
|
53
|
-
return
|
|
56
|
+
return False
|
|
54
57
|
script = """
|
|
55
58
|
if redis.call("get", KEYS[1]) == ARGV[1] then
|
|
56
59
|
return redis.call("del", KEYS[1])
|
|
@@ -58,4 +61,10 @@ class RedisLock:
|
|
|
58
61
|
return 0
|
|
59
62
|
end
|
|
60
63
|
"""
|
|
61
|
-
|
|
64
|
+
try:
|
|
65
|
+
self.client.client.eval(script, 1, self.name, self.token)
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.error(f"Error releasing lock '{self.name}': {e}")
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
return None
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import threading
|
|
3
|
+
import json
|
|
3
4
|
from typing import Callable
|
|
4
5
|
|
|
5
6
|
from redis_simplify.mixins.decorator_metrics import recorded
|
|
@@ -27,7 +28,6 @@ class PubSubMixin:
|
|
|
27
28
|
|
|
28
29
|
def publish_json(self, channel: str, data: dict) -> int:
|
|
29
30
|
"""Publica JSON em canal"""
|
|
30
|
-
import json
|
|
31
31
|
return self.publish(channel, json.dumps(data))
|
|
32
32
|
|
|
33
33
|
def subscribe(self, channel: str, callback: Callable, pattern: bool = False):
|
|
@@ -43,13 +43,13 @@ class PubSubMixin:
|
|
|
43
43
|
else:
|
|
44
44
|
pubsub.subscribe(channel)
|
|
45
45
|
|
|
46
|
-
#
|
|
47
|
-
|
|
46
|
+
# Variável para controlar o loop
|
|
47
|
+
stop_event = threading.Event()
|
|
48
48
|
|
|
49
49
|
def listener():
|
|
50
50
|
try:
|
|
51
51
|
for message in pubsub.listen():
|
|
52
|
-
if
|
|
52
|
+
if stop_event.is_set():
|
|
53
53
|
break
|
|
54
54
|
if message['type'] in ('message', 'pmessage'):
|
|
55
55
|
data = message.get('data')
|
|
@@ -69,25 +69,30 @@ class PubSubMixin:
|
|
|
69
69
|
|
|
70
70
|
# Armazena para fechar depois
|
|
71
71
|
self._pubsubs.append(pubsub)
|
|
72
|
-
self._pubsub_threads.append((thread, pubsub,
|
|
72
|
+
self._pubsub_threads.append((thread, pubsub, stop_event))
|
|
73
73
|
|
|
74
74
|
logger.info(f"Subscribed to {channel}")
|
|
75
75
|
return pubsub
|
|
76
76
|
|
|
77
77
|
def close_pubsubs(self):
|
|
78
78
|
"""Fecha todas as subscriptions ativas"""
|
|
79
|
-
for pubsub in self.
|
|
80
|
-
|
|
81
|
-
pubsub.close()
|
|
82
|
-
except:
|
|
83
|
-
pass
|
|
84
|
-
self._pubsubs.clear()
|
|
79
|
+
for thread, pubsub, stop_event in self._pubsub_threads:
|
|
80
|
+
stop_event.set() # Sinaliza para parar
|
|
85
81
|
|
|
86
82
|
# Aguarda threads terminarem
|
|
87
|
-
for thread, pubsub,
|
|
83
|
+
for thread, pubsub, stop_event in self._pubsub_threads:
|
|
88
84
|
try:
|
|
89
85
|
if thread.is_alive():
|
|
90
86
|
thread.join(timeout=0.5)
|
|
91
87
|
except:
|
|
92
88
|
pass
|
|
89
|
+
|
|
90
|
+
# Fecha pubsubs
|
|
91
|
+
for pubsub in self._pubsubs:
|
|
92
|
+
try:
|
|
93
|
+
pubsub.close()
|
|
94
|
+
except:
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
self._pubsubs.clear()
|
|
93
98
|
self._pubsub_threads.clear()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: redis-simplify
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.4
|
|
4
4
|
Summary: Convenience wrapper for Redis - connection, JSON helpers, and automatic reconnection
|
|
5
5
|
Author-email: Paulo Ricardo Tebet Lyrio <tebetpaulo91@yahoo.com>
|
|
6
6
|
License: MIT
|
|
@@ -383,6 +383,7 @@ DEBUG:redis_simplify.client:Get test: hello world...
|
|
|
383
383
|
| `rate_limit_check(key, max_requests, window_seconds)` | Check if action is allowed |
|
|
384
384
|
| `rate_limit_remaining(key, max_requests, window_seconds)` | Get remaining requests |
|
|
385
385
|
| `rate_limit_reset(key, window_seconds)` | Get seconds until reset |
|
|
386
|
+
| `run_with_rate_limit(operation, rate_key, max_requests, window_seconds, *args, **kwargs)` | Execute operation with automatic rate limit |
|
|
386
387
|
|
|
387
388
|
### Distributed Lock
|
|
388
389
|
| Method | Description |
|
|
@@ -433,7 +434,7 @@ DEBUG:redis_simplify.client:Get test: hello world...
|
|
|
433
434
|
| `ping()` | Verify connectivity |
|
|
434
435
|
| `pipeline()` | Create a Redis pipeline |
|
|
435
436
|
| `scan(cursor=0, match=None, count=None)` | Iterate keys using SCAN |
|
|
436
|
-
| `
|
|
437
|
+
| `flushall()` | Remove all Redis databases |
|
|
437
438
|
| `close()` | Close the connection |
|
|
438
439
|
| `set_log_level(level)` | Change log level at runtime|
|
|
439
440
|
|
|
@@ -136,8 +136,8 @@ class TestRedisClientLogging:
|
|
|
136
136
|
|
|
137
137
|
caplog.clear()
|
|
138
138
|
|
|
139
|
-
#
|
|
140
|
-
client.
|
|
139
|
+
# flushall gera warning
|
|
140
|
+
client.flushall()
|
|
141
141
|
|
|
142
142
|
# Deve ter pelo menos uma mensagem WARNING
|
|
143
143
|
warning_messages = [r for r in caplog.records if r.levelno == logging.WARNING]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|