userver: en/testsuite/databases/rabbitmq/classes.py Source File
Loading...
Searching...
No Matches
classes.py
1import asyncio
2import dataclasses
3
4import aio_pika
5
6
7class BaseError(Exception):
8 pass
9
10
12 pass
13
14
15@dataclasses.dataclass(frozen=True)
17 """RabbitMQ connection parameters"""
18
19 host: str
20 tcp_port: int
21
22
23class Channel:
24 def __init__(self, channel: aio_pika.Channel):
25 self._channel = channel
26
27 async def __aenter__(self) -> 'Channel':
28 if not self._channel.is_initialized:
29 await self._channel.initialize()
30 return self
31
32 async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
33 await self._channel.close(exc_val)
34
35 async def declare_exchange(
36 self,
37 exchange: str,
38 exchange_type: aio_pika.ExchangeType,
39 timeout: float = 1.0,
40 ) -> None:
41 await self._channel.declare_exchange(
42 name=exchange,
43 type=exchange_type,
44 timeout=timeout,
45 )
46
47 async def declare_queue(self, queue: str, timeout: float = 1.0) -> None:
48 await self._channel.declare_queue(
49 name=queue,
50 durable=True,
51 timeout=timeout,
52 )
53
54 async def bind_queue(
55 self,
56 exchange: str,
57 queue: str,
58 routing_key: str,
59 timeout: float = 1.0,
60 ):
61 async def _do_bind():
62 rmq_queue = await self._channel.get_queue(queue)
63 await rmq_queue.bind(exchange=exchange, routing_key=routing_key)
64
65 await asyncio.wait_for(_do_bind(), timeout=timeout)
66
67 async def publish(
68 self,
69 exchange: str,
70 routing_key: str,
71 body: bytes,
72 timeout: float = 1.0,
73 ):
74 async def _do_publish():
75 rmq_exchange = await self._channel.get_exchange(name=exchange)
76 await rmq_exchange.publish(
77 aio_pika.Message(body=body),
78 routing_key=routing_key,
79 )
80
81 await asyncio.wait_for(_do_publish(), timeout=timeout)
82
83 async def consume(self, queue: str, count: int, timeout: float = 2.0):
84 async def _do_consume():
85 result = []
86
87 rmq_queue = await self._channel.get_queue(name=queue)
88
89 for i in range(count):
90 incoming_message = await rmq_queue.get()
91 if incoming_message is not None:
92 await incoming_message.ack()
93 result.append(
94 incoming_message.body[: incoming_message.body_size],
95 )
96
97 return result
98
99 return await asyncio.wait_for(_do_consume(), timeout=timeout)
100
101
102class Client:
103 def __init__(self, connection_future):
104 self._connection_future = connection_future
105 self._connection = None
106
107 async def teardown(self):
108 if self._connection is not None:
109 await self._connection.close()
110
111 async def get_channel(self) -> Channel:
112 if self._connection is None:
113 self._connection = await self._connection_future
114 return Channel(
115 channel=self._connection.channel(publisher_confirms=True),
116 )
117
118
120 def __init__(self, enabled: bool, conn_info: ConnectionInfo):
121 self._enabled = enabled
122 if self._enabled:
123 self._client = Client(
124 connection_future=aio_pika.connect_robust(
125 host=conn_info.host,
126 port=conn_info.tcp_port,
127 timeout=2.0,
128 ),
129 )
130
131 async def teardown(self):
132 if self._enabled:
133 await self._client.teardown()
134
135 async def get_channel(self) -> Channel:
136 if not self._enabled:
137 raise RabbitMqDisabledError
138
139 return await self._client.get_channel()