Skip to content

Commit c10881f

Browse files
committed
Merge branch 'release/0.5.3'
2 parents 039bd53 + 6a29f1b commit c10881f

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

Diff for: pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "taskiq-redis"
3-
version = "0.5.2"
3+
version = "0.5.3"
44
description = "Redis integration for taskiq"
55
authors = ["taskiq-team <taskiq@norely.com>"]
66
readme = "README.md"

Diff for: taskiq_redis/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
RedisAsyncResultBackend,
55
)
66
from taskiq_redis.redis_broker import ListQueueBroker, PubSubBroker
7+
from taskiq_redis.redis_cluster_broker import ListQueueClusterBroker
78
from taskiq_redis.schedule_source import RedisScheduleSource
89

910
__all__ = [
1011
"RedisAsyncClusterResultBackend",
1112
"RedisAsyncResultBackend",
1213
"ListQueueBroker",
1314
"PubSubBroker",
15+
"ListQueueClusterBroker",
1416
"RedisScheduleSource",
1517
]

Diff for: taskiq_redis/redis_cluster_broker.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from typing import Any, AsyncGenerator
2+
3+
from redis.asyncio import RedisCluster
4+
from taskiq.abc.broker import AsyncBroker
5+
from taskiq.message import BrokerMessage
6+
7+
8+
class BaseRedisClusterBroker(AsyncBroker):
9+
"""Base broker that works with Redis Cluster."""
10+
11+
def __init__(
12+
self,
13+
url: str,
14+
queue_name: str = "taskiq",
15+
max_connection_pool_size: int = 2**31,
16+
**connection_kwargs: Any,
17+
) -> None:
18+
"""
19+
Constructs a new broker.
20+
21+
:param url: url to redis.
22+
:param queue_name: name for a list in redis.
23+
:param max_connection_pool_size: maximum number of connections in pool.
24+
:param connection_kwargs: additional arguments for aio-redis ConnectionPool.
25+
"""
26+
super().__init__()
27+
28+
self.redis: RedisCluster[bytes] = RedisCluster.from_url(
29+
url=url,
30+
max_connections=max_connection_pool_size,
31+
**connection_kwargs,
32+
)
33+
34+
self.queue_name = queue_name
35+
36+
async def shutdown(self) -> None:
37+
"""Closes redis connection pool."""
38+
await self.redis.aclose() # type: ignore[attr-defined]
39+
await super().shutdown()
40+
41+
42+
class ListQueueClusterBroker(BaseRedisClusterBroker):
43+
"""Broker that works with Redis Cluster and distributes tasks between workers."""
44+
45+
async def kick(self, message: BrokerMessage) -> None:
46+
"""
47+
Put a message in a list.
48+
49+
This method appends a message to the list of all messages.
50+
51+
:param message: message to append.
52+
"""
53+
await self.redis.lpush(self.queue_name, message.message) # type: ignore[attr-defined]
54+
55+
async def listen(self) -> AsyncGenerator[bytes, None]:
56+
"""
57+
Listen redis queue for new messages.
58+
59+
This function listens to the queue
60+
and yields new messages if they have BrokerMessage type.
61+
62+
:yields: broker messages.
63+
"""
64+
redis_brpop_data_position = 1
65+
while True:
66+
value = await self.redis.brpop([self.queue_name]) # type: ignore[attr-defined]
67+
yield value[redis_brpop_data_position]

Diff for: tests/test_broker.py

+28-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import pytest
66
from taskiq import AckableMessage, AsyncBroker, BrokerMessage
77

8-
from taskiq_redis import ListQueueBroker, PubSubBroker
8+
from taskiq_redis import ListQueueBroker, ListQueueClusterBroker, PubSubBroker
99

1010

1111
def test_no_url_should_raise_typeerror() -> None:
@@ -96,3 +96,30 @@ async def test_list_queue_broker(
9696
worker1_task.cancel()
9797
worker2_task.cancel()
9898
await broker.shutdown()
99+
100+
101+
@pytest.mark.anyio
102+
async def test_list_queue_cluster_broker(
103+
valid_broker_message: BrokerMessage,
104+
redis_cluster_url: str,
105+
) -> None:
106+
"""
107+
Test that messages are published and read correctly by ListQueueClusterBroker.
108+
109+
We create two workers that listen and send a message to them.
110+
Expect only one worker to receive the same message we sent.
111+
"""
112+
broker = ListQueueClusterBroker(
113+
url=redis_cluster_url,
114+
queue_name=uuid.uuid4().hex,
115+
)
116+
worker_task = asyncio.create_task(get_message(broker))
117+
await asyncio.sleep(0.3)
118+
119+
await broker.kick(valid_broker_message)
120+
await asyncio.sleep(0.3)
121+
122+
assert worker_task.done()
123+
assert worker_task.result() == valid_broker_message.message
124+
worker_task.cancel()
125+
await broker.shutdown()

0 commit comments

Comments
 (0)