@@ -455,6 +455,44 @@ async def test_reconnect_and_resent_non_acked_messages_on_retriable_error(
455455 second_writer .from_server .put_nowait (self .make_default_ack_message (seq_no = 2 ))
456456 await reconnector .close (flush = True )
457457
458+ async def test_reconnect_on_cancelled_error_from_receive (self , default_driver , default_settings , monkeypatch ):
459+ stream_creates = 0
460+ stream_2_created = asyncio .Event ()
461+
462+ class StreamWriterCancelOnFirstReceive (TestWriterAsyncIOReconnector .StreamWriterMock ):
463+ def __init__ (self ):
464+ super ().__init__ ()
465+ self ._first_receive = True
466+
467+ async def receive (self ):
468+ if self ._first_receive :
469+ self ._first_receive = False
470+ raise asyncio .CancelledError ()
471+ await asyncio .Future () # stream 2 stays alive
472+
473+ async def create_mock (* args , ** kwargs ):
474+ nonlocal stream_creates
475+ stream_creates += 1
476+ writer = StreamWriterCancelOnFirstReceive ()
477+ writer .last_seqno = TestWriterAsyncIOReconnector .init_last_seqno
478+ if stream_creates >= 2 :
479+ stream_2_created .set ()
480+ return writer
481+
482+ with mock .patch .object (WriterAsyncIOStream , "create" , create_mock ):
483+ reconnector = WriterAsyncIOReconnector (default_driver , default_settings )
484+ try :
485+ # Bug: stream 2 is never created — _stop(CancelledError) kills the writer permanently.
486+ # After the fix: writer reconnects and stream 2 is created.
487+ await asyncio .wait_for (stream_2_created .wait (), timeout = 2.0 )
488+ except asyncio .TimeoutError :
489+ pytest .fail (
490+ "Writer did not reconnect after CancelledError from receive() — "
491+ "bug: _stop(CancelledError) permanently kills writer"
492+ )
493+ finally :
494+ await reconnector .close (False )
495+
458496 async def test_stop_on_unexpected_exception (self , reconnector : WriterAsyncIOReconnector , get_stream_writer ):
459497 class TestException (Exception ):
460498 pass
0 commit comments