encode / broadcaster

Broadcast channels for async web apps. 📢
BSD 3-Clause "New" or "Revised" License
1.13k stars 121 forks source link

Fix subscriber not properly unsubscribing when an exception is raised inside the context manager #112

Closed jolorke closed 8 months ago

jolorke commented 8 months ago

Turned out to be a duplicate of this: https://github.com/encode/broadcaster/pull/58

But this one also contains testcases :)

alex-oleshkevich commented 8 months ago

I get this exception when running pytest. Python 3.11.8

Exception ignored in: <coroutine object Broadcast._listener at 0x7363387bac50>
Traceback (most recent call last):
  File "/home/alex/projects/broadcaster/broadcaster/_base.py", line 74, in _listener
    event = await self._backend.next_published()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/alex/projects/broadcaster/broadcaster/_backends/memory.py", line 30, in next_published
    event = await self._published.get()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/queues.py", line 160, in get
    getter.cancel()  # Just in case getter is not done yet.
    ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/base_events.py", line 762, in call_soon
    self._check_closed()
  File "/usr/lib/python3.11/asyncio/base_events.py", line 520, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Task was destroyed but it is pending!
task: <Task pending name='Task-11' coro=<Broadcast._listener() done, defined at /home/alex/projects/broadcaster/broadcaster/_base.py:72> wait_for=<Future cancelled>>
Exception ignored in: <coroutine object Broadcast._listener at 0x7363387bb3d0>
Traceback (most recent call last):
  File "/home/alex/projects/broadcaster/broadcaster/_base.py", line 74, in _listener
    event = await self._backend.next_published()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/alex/projects/broadcaster/broadcaster/_backends/memory.py", line 30, in next_published
    event = await self._published.get()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/queues.py", line 160, in get
    getter.cancel()  # Just in case getter is not done yet.
    ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/base_events.py", line 762, in call_soon
    self._check_closed()
  File "/usr/lib/python3.11/asyncio/base_events.py", line 520, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Task was destroyed but it is pending!
task: <Task pending name='Task-13' coro=<Broadcast._listener() done, defined at /home/alex/projects/broadcaster/broadcaster/_base.py:72> wait_for=<Future cancelled>>
jolorke commented 8 months ago

Thanks!