Skip to content

Commit a19671d

Browse files
authored
Merge pull request #533 from mosquito/featire/wait-reopen-channel-state
Feature/wait reopen channel state
2 parents 6d4c8a9 + 87617bf commit a19671d

31 files changed

Lines changed: 634 additions & 397 deletions

CHANGELOG.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
9.1.0
2+
-----
3+
4+
The bulk of the changes are related to how the library entities are now
5+
interconnected. In previous versions of `aio_pika.Channel` instances not
6+
contains a link to the `aio_pika.Connection` instances for now is contains it.
7+
8+
While I don't want custom code to work directly with the `aiormq.Channel`
9+
instance, this was a public API and I should warn you about the change here.
10+
The `aio_pika.Channel.channel` property is deprecated. Use
11+
`aio_pika.Channel.get_underlay_chanel()` instead.
12+
Now all library entities already use this method.
13+
14+
115
9.0.7
216
-----
317

@@ -17,9 +31,9 @@
1731
-----
1832

1933
* Prevent 'Task exception was never retrieved' #524
20-
If future.exception() is not called (even on cancelled futures), it seems Python
21-
will then log 'Task exception was never retrieved'. Rewriting this logic
22-
slightly should hopefully achieve the same functionality while
34+
If future.exception() is not called (even on cancelled futures), it seems Python
35+
will then log 'Task exception was never retrieved'. Rewriting this logic
36+
slightly should hopefully achieve the same functionality while
2337
preventing the Python errors.
2438
* Avoid implicitly depending on setuptools #526
2539

Makefile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
all: test
22

3-
RABBITMQ_CONTAINER_NAME:=aio_pika_rabbitmq
43
RABBITMQ_IMAGE:=mosquito/aiormq-rabbitmq
54

65
test:
76
find . -name "*.pyc" -type f -delete
87
tox
98

109
rabbitmq:
10+
docker kill $(docker ps -f label=aio-pika.rabbitmq -q) || true
1111
docker pull $(RABBITMQ_IMAGE)
12-
docker kill $(RABBITMQ_CONTAINER_NAME) || true
1312
docker run --rm -d \
14-
--name $(RABBITMQ_CONTAINER_NAME) \
13+
-l aio-pika.rabbitmq \
1514
-p 5671:5671 \
1615
-p 5672:5672 \
1716
-p 15671:15671 \

aio_pika/abc.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Generator, Iterator, Optional, Type, TypeVar, Union, overload,
1212
)
1313

14+
1415
if sys.version_info >= (3, 8):
1516
from typing import Literal, TypedDict
1617
else:
@@ -81,11 +82,6 @@ class DeclarationResult:
8182
class AbstractTransaction:
8283
state: TransactionState
8384

84-
@property
85-
@abstractmethod
86-
def channel(self) -> "AbstractChannel":
87-
raise NotImplementedError
88-
8985
@abstractmethod
9086
async def select(
9187
self, timeout: TimeoutType = None,
@@ -244,7 +240,7 @@ async def __aexit__(
244240

245241

246242
class AbstractQueue:
247-
channel: aiormq.abc.AbstractChannel
243+
channel: "AbstractChannel"
248244
name: str
249245
durable: bool
250246
exclusive: bool
@@ -307,7 +303,7 @@ async def unbind(
307303
@abstractmethod
308304
async def consume(
309305
self,
310-
callback: Callable[[AbstractIncomingMessage], Any],
306+
callback: Callable[[AbstractIncomingMessage], Awaitable[Any]],
311307
no_ack: bool = False,
312308
exclusive: bool = False,
313309
arguments: Arguments = None,
@@ -409,7 +405,7 @@ class AbstractExchange(ABC):
409405
@abstractmethod
410406
def __init__(
411407
self,
412-
channel: aiormq.abc.AbstractChannel,
408+
channel: "AbstractChannel",
413409
name: str,
414410
type: Union[ExchangeType, str] = ExchangeType.DIRECT,
415411
*,
@@ -528,9 +524,8 @@ def is_closed(self) -> bool:
528524
def close(self, exc: Optional[ExceptionType] = None) -> Awaitable[None]:
529525
raise NotImplementedError
530526

531-
@property
532527
@abstractmethod
533-
def channel(self) -> aiormq.abc.AbstractChannel:
528+
async def get_underlay_channel(self) -> aiormq.abc.AbstractChannel:
534529
raise NotImplementedError
535530

536531
@property
@@ -760,7 +755,7 @@ async def update_secret(
760755

761756
class AbstractRobustQueue(AbstractQueue):
762757
@abstractmethod
763-
def restore(self, channel: aiormq.abc.AbstractChannel) -> Awaitable[None]:
758+
def restore(self) -> Awaitable[None]:
764759
raise NotImplementedError
765760

766761
@abstractmethod
@@ -791,7 +786,7 @@ async def consume(
791786

792787
class AbstractRobustExchange(AbstractExchange):
793788
@abstractmethod
794-
def restore(self, channel: aiormq.abc.AbstractChannel) -> Awaitable[None]:
789+
def restore(self) -> Awaitable[None]:
795790
raise NotImplementedError
796791

797792
@abstractmethod
@@ -815,7 +810,7 @@ def reopen(self) -> Awaitable[None]:
815810
raise NotImplementedError
816811

817812
@abstractmethod
818-
async def restore(self, connection: aiormq.abc.AbstractConnection) -> None:
813+
async def restore(self) -> None:
819814
raise NotImplementedError
820815

821816
@abstractmethod

aio_pika/channel.py

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import warnings
23
from abc import ABC
34
from types import TracebackType
45
from typing import Any, AsyncContextManager, Generator, Optional, Type, Union
@@ -9,9 +10,10 @@
910
from pamqp.common import Arguments
1011

1112
from .abc import (
12-
AbstractChannel, AbstractExchange, AbstractQueue, TimeoutType,
13-
UnderlayChannel,
13+
AbstractChannel, AbstractConnection, AbstractExchange, AbstractQueue,
14+
TimeoutType, UnderlayChannel,
1415
)
16+
from .exceptions import ChannelInvalidStateError
1517
from .exchange import Exchange, ExchangeType
1618
from .log import get_logger
1719
from .message import IncomingMessage
@@ -52,7 +54,7 @@ class Channel(ChannelContext):
5254

5355
def __init__(
5456
self,
55-
connection: aiormq.abc.AbstractConnection,
57+
connection: AbstractConnection,
5658
channel_number: Optional[int] = None,
5759
publisher_confirms: bool = True,
5860
on_return_raises: bool = False,
@@ -73,12 +75,12 @@ def __init__(
7375
'without "publisher_confirms"',
7476
)
7577

76-
self._connection: aiormq.abc.AbstractConnection = connection
78+
self._connection: AbstractConnection = connection
7779

7880
# That's means user closed channel instance explicitly
7981
self._closed: bool = False
8082

81-
self._channel = None
83+
self._channel: Optional[UnderlayChannel] = None
8284
self._channel_number = channel_number
8385

8486
self.close_callbacks = CallbackCollection(self)
@@ -99,9 +101,10 @@ def is_closed(self) -> bool:
99101
side or after the close() method has been called."""
100102
if not self.is_initialized or self._closed:
101103
return True
102-
if not self._channel:
104+
channel = self._channel
105+
if channel is None:
103106
return True
104-
return self._channel.channel.is_closed
107+
return channel.channel.is_closed
105108

106109
async def close(
107110
self,
@@ -119,45 +122,58 @@ async def close(
119122
self._closed = True
120123
await self._channel.close()
121124

122-
@property
123-
def channel(self) -> aiormq.abc.AbstractChannel:
125+
async def get_underlay_channel(self) -> aiormq.abc.AbstractChannel:
124126

125127
if not self.is_initialized or not self._channel:
126128
raise aiormq.exceptions.ChannelInvalidStateError(
127129
"Channel was not opened",
128130
)
129131

130-
if self.is_closed:
131-
raise aiormq.exceptions.ChannelInvalidStateError(
132-
"Channel has been closed",
133-
)
132+
return self._channel.channel
134133

134+
@property
135+
def channel(self) -> aiormq.abc.AbstractChannel:
136+
warnings.warn(
137+
"This property is deprecated, do not use this anymore.",
138+
DeprecationWarning,
139+
)
140+
if self._channel is None:
141+
raise aiormq.exceptions.ChannelInvalidStateError
135142
return self._channel.channel
136143

137144
@property
138145
def number(self) -> Optional[int]:
139-
return (
140-
self.channel.number
141-
if self.is_initialized
142-
else self._channel_number
143-
)
146+
if self._channel is None:
147+
return self._channel_number
148+
149+
underlay_channel: UnderlayChannel = self._channel
150+
return underlay_channel.channel.number
144151

145152
def __str__(self) -> str:
146153
return "{}".format(self.number or "Not initialized channel")
147154

148155
async def _open(self) -> None:
149156
await self._connection.ready()
150157

158+
transport = self._connection.transport
159+
if transport is None:
160+
raise ChannelInvalidStateError("No active transport in channel")
161+
151162
channel = await UnderlayChannel.create(
152-
self._connection,
163+
transport.connection,
153164
self._on_close,
154165
publisher_confirms=self.publisher_confirms,
155166
on_return_raises=self.on_return_raises,
156167
channel_number=self._channel_number,
157168
)
158169

159-
await self._on_open(channel.channel)
160170
self._channel = channel
171+
try:
172+
await self._on_open()
173+
except BaseException as e:
174+
await channel.close(e)
175+
self._channel = None
176+
raise
161177
self._closed = False
162178

163179
async def initialize(self, timeout: TimeoutType = None) -> None:
@@ -169,9 +185,9 @@ async def initialize(self, timeout: TimeoutType = None) -> None:
169185
await self._open()
170186
await self._on_initialized()
171187

172-
async def _on_open(self, channel: aiormq.abc.AbstractChannel) -> None:
188+
async def _on_open(self) -> None:
173189
self.default_exchange: Exchange = self.EXCHANGE_CLASS(
174-
channel=channel,
190+
channel=self,
175191
arguments=None,
176192
auto_delete=False,
177193
durable=False,
@@ -192,7 +208,8 @@ async def _on_close(self, closing: asyncio.Future) -> None:
192208
self._channel.channel.on_return_callbacks.discard(self._on_return)
193209

194210
async def _on_initialized(self) -> None:
195-
self.channel.on_return_callbacks.add(self._on_return)
211+
channel = await self.get_underlay_channel()
212+
channel.on_return_callbacks.add(self._on_return)
196213

197214
def _on_return(self, message: aiormq.abc.DeliveredMessage) -> None:
198215
self.return_callbacks(IncomingMessage(message, no_ack=True))
@@ -241,7 +258,7 @@ async def declare_exchange(
241258
durable = False
242259

243260
exchange = self.EXCHANGE_CLASS(
244-
channel=self.channel,
261+
channel=self,
245262
name=name,
246263
type=type,
247264
durable=durable,
@@ -281,7 +298,7 @@ async def get_exchange(
281298
return await self.declare_exchange(name=name, passive=True)
282299
else:
283300
return self.EXCHANGE_CLASS(
284-
channel=self.channel,
301+
channel=self,
285302
name=name,
286303
durable=False,
287304
auto_delete=False,
@@ -321,7 +338,7 @@ async def declare_queue(
321338
"""
322339

323340
queue: AbstractQueue = self.QUEUE_CLASS(
324-
channel=self.channel,
341+
channel=self,
325342
name=name,
326343
durable=durable,
327344
exclusive=exclusive,
@@ -358,7 +375,7 @@ async def get_queue(
358375
return await self.declare_queue(name=name, passive=True)
359376
else:
360377
return self.QUEUE_CLASS(
361-
channel=self.channel,
378+
channel=self,
362379
name=name,
363380
durable=False,
364381
exclusive=False,
@@ -379,7 +396,9 @@ async def set_qos(
379396
warn('Use "global_" instead of "all_channels"', DeprecationWarning)
380397
global_ = all_channels
381398

382-
return await self.channel.basic_qos(
399+
channel = await self.get_underlay_channel()
400+
401+
return await channel.basic_qos(
383402
prefetch_count=prefetch_count,
384403
prefetch_size=prefetch_size,
385404
global_=global_,
@@ -394,7 +413,8 @@ async def queue_delete(
394413
if_empty: bool = False,
395414
nowait: bool = False,
396415
) -> aiormq.spec.Queue.DeleteOk:
397-
return await self.channel.queue_delete(
416+
channel = await self.get_underlay_channel()
417+
return await channel.queue_delete(
398418
queue=queue_name,
399419
if_unused=if_unused,
400420
if_empty=if_empty,
@@ -409,7 +429,8 @@ async def exchange_delete(
409429
if_unused: bool = False,
410430
nowait: bool = False,
411431
) -> aiormq.spec.Exchange.DeleteOk:
412-
return await self.channel.exchange_delete(
432+
channel = await self.get_underlay_channel()
433+
return await channel.exchange_delete(
413434
exchange=exchange_name,
414435
if_unused=if_unused,
415436
nowait=nowait,
@@ -426,7 +447,8 @@ def transaction(self) -> Transaction:
426447
return Transaction(self)
427448

428449
async def flow(self, active: bool = True) -> aiormq.spec.Channel.FlowOk:
429-
return await self.channel.flow(active=active)
450+
channel = await self.get_underlay_channel()
451+
return await channel.flow(active=active)
430452

431453

432454
__all__ = ("Channel",)

0 commit comments

Comments
 (0)