Skip to content

Commit 432caeb

Browse files
authored
Merge pull request #12 from booqoffsky/issue-11
Split Broker into PubSubBroker and ListQueueBroker
2 parents 74c3876 + 311d7f8 commit 432caeb

File tree

3 files changed

+64
-45
lines changed

3 files changed

+64
-45
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,19 @@ pip install taskiq-redis
1616
# Usage
1717

1818
Let's see the example with the redis broker and redis async result:
19+
1920
```python
2021
import asyncio
2122

22-
from taskiq_redis.redis_broker import RedisBroker
23+
from taskiq_redis.redis_broker import ListQueueBroker
2324
from taskiq_redis.redis_backend import RedisAsyncResultBackend
2425

25-
2626
redis_async_result = RedisAsyncResultBackend(
2727
redis_url="redis://localhost:6379",
2828
)
2929

30-
broker = RedisBroker(
30+
# Or you can use PubSubBroker if you need broadcasting
31+
broker = ListQueueBroker(
3132
url="redis://localhost:6379",
3233
result_backend=redis_async_result,
3334
)

taskiq_redis/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""Package for redis integration."""
22
from taskiq_redis.redis_backend import RedisAsyncResultBackend
3-
from taskiq_redis.redis_broker import RedisBroker
3+
from taskiq_redis.redis_broker import ListQueueBroker
44

5-
__all__ = ["RedisAsyncResultBackend", "RedisBroker"]
5+
__all__ = ["RedisAsyncResultBackend", "ListQueueBroker"]

taskiq_redis/redis_broker.py

Lines changed: 58 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pickle
2+
from abc import abstractmethod
23
from logging import getLogger
34
from typing import Any, AsyncGenerator, Callable, Optional, TypeVar
45

@@ -12,8 +13,8 @@
1213
logger = getLogger("taskiq.redis_broker")
1314

1415

15-
class RedisBroker(AsyncBroker):
16-
"""Broker that works with Redis."""
16+
class BaseRedisBroker(AsyncBroker):
17+
"""Base broker that works with Redis."""
1718

1819
def __init__(
1920
self,
@@ -44,31 +45,12 @@ def __init__(
4445
max_connections=max_connection_pool_size,
4546
**connection_kwargs,
4647
)
47-
48-
self.redis_pubsub_channel = queue_name
48+
self.queue_name = queue_name
4949

5050
async def shutdown(self) -> None:
5151
"""Closes redis connection pool."""
5252
await self.connection_pool.disconnect()
5353

54-
async def kick(self, message: BrokerMessage) -> None:
55-
"""
56-
Sends a message to the redis broker list.
57-
58-
This function constructs message for redis
59-
and sends it.
60-
61-
The message is pickled dict object with message,
62-
task_id, task_name and labels.
63-
64-
:param message: message to send.
65-
"""
66-
async with Redis(connection_pool=self.connection_pool) as redis_conn:
67-
await redis_conn.publish(
68-
self.redis_pubsub_channel,
69-
pickle.dumps(message),
70-
)
71-
7254
async def listen(self) -> AsyncGenerator[BrokerMessage, None]:
7355
"""
7456
Listen redis queue for new messages.
@@ -78,24 +60,60 @@ async def listen(self) -> AsyncGenerator[BrokerMessage, None]:
7860
7961
:yields: broker messages.
8062
"""
63+
async for message in self._listen_to_raw_messages():
64+
try:
65+
redis_message = pickle.loads(message)
66+
if isinstance(redis_message, BrokerMessage):
67+
yield redis_message
68+
except (
69+
TypeError,
70+
AttributeError,
71+
pickle.UnpicklingError,
72+
) as exc:
73+
logger.debug(
74+
"Cannot read broker message %s",
75+
exc,
76+
exc_info=True,
77+
)
78+
79+
@abstractmethod
80+
async def _listen_to_raw_messages(self) -> AsyncGenerator[bytes, None]:
81+
"""
82+
Generator for reading raw data from Redis.
83+
84+
:yields: raw data.
85+
"""
86+
yield # type: ignore
87+
88+
89+
class PubSubBroker(BaseRedisBroker):
90+
"""Broker that works with Redis and broadcasts tasks to all workers."""
91+
92+
async def kick(self, message: BrokerMessage) -> None: # noqa: D102
93+
async with Redis(connection_pool=self.connection_pool) as redis_conn:
94+
await redis_conn.publish(self.queue_name, pickle.dumps(message))
95+
96+
async def _listen_to_raw_messages(self) -> AsyncGenerator[bytes, None]:
8197
async with Redis(connection_pool=self.connection_pool) as redis_conn:
8298
redis_pubsub_channel = redis_conn.pubsub()
83-
await redis_pubsub_channel.subscribe(self.redis_pubsub_channel)
99+
await redis_pubsub_channel.subscribe(self.queue_name)
84100
async for message in redis_pubsub_channel.listen():
85-
if message:
86-
try:
87-
redis_message = pickle.loads(
88-
message["data"],
89-
)
90-
if isinstance(redis_message, BrokerMessage):
91-
yield redis_message
92-
except (
93-
TypeError,
94-
AttributeError,
95-
pickle.UnpicklingError,
96-
) as exc:
97-
logger.debug(
98-
"Cannot read broker message %s",
99-
exc,
100-
exc_info=True,
101-
)
101+
if not message:
102+
continue
103+
yield message["data"]
104+
105+
106+
class ListQueueBroker(BaseRedisBroker):
107+
"""Broker that works with Redis and distributes tasks between workers."""
108+
109+
async def kick(self, message: BrokerMessage) -> None: # noqa: D102
110+
async with Redis(connection_pool=self.connection_pool) as redis_conn:
111+
await redis_conn.lpush(self.queue_name, pickle.dumps(message))
112+
113+
async def _listen_to_raw_messages(self) -> AsyncGenerator[bytes, None]:
114+
redis_brpop_data_position = 1
115+
async with Redis(connection_pool=self.connection_pool) as redis_conn:
116+
while True: # noqa: WPS457
117+
yield (await redis_conn.brpop(self.queue_name))[
118+
redis_brpop_data_position
119+
]

0 commit comments

Comments
 (0)