Skip to content

ProactorEventLoop datagram transports drop buffered datagrams on close() and never call connection_lost() #156920

Description

@graingert

Bug report

Bug description:

Closing a datagram transport that still has datagrams queued drops them and
never calls connection_lost(), so the socket is closed only by __del__,
with a ResourceWarning; SelectorEventLoop flushes them and tears down
normally. _ProactorDatagramTransport._loop_writing() returns at
if self._conn_lost: return, which close() has just incremented, so the
teardown branch below it -- the one close() deliberately leaves to the
write loop when the buffer is non-empty -- is unreachable.

Reproducer

import asyncio
import sys


async def main():
    loop = asyncio.get_running_loop()
    print(sys.version)
    print(type(loop).__name__)
    received = []
    lost = loop.create_future()

    class Receiver(asyncio.DatagramProtocol):
        def datagram_received(self, data, addr):
            received.append(data)

    class Sender(asyncio.DatagramProtocol):
        def connection_lost(self, exc):
            if not lost.done():
                lost.set_result(exc)

    recv_transport, _ = await loop.create_datagram_endpoint(
        Receiver, local_addr=('127.0.0.1', 0))
    addr = recv_transport.get_extra_info('sockname')

    transport, _ = await loop.create_datagram_endpoint(
        Sender, remote_addr=addr)

    for i in range(5):
        transport.sendto(b'datagram-%d' % i)
    transport.close()

    try:
        await asyncio.wait_for(lost, 5)
    except TimeoutError:
        print('connection_lost(): never called')
    else:
        print('connection_lost(): called')

    await asyncio.sleep(0.5)
    print('datagrams received:', len(received))
    print('write buffer size: ', transport.get_write_buffer_size())
    recv_transport.close()
    await asyncio.sleep(0)


asyncio.run(main(), loop_factory=asyncio.SelectorEventLoop)
asyncio.run(main(), loop_factory=asyncio.ProactorEventLoop)

Output on Windows:

PS C:\Users\tagra\projects\cpython> py -3.14 .\reproducer.py
3.14.7 (tags/v3.14.7:823f032, Aug  5 2026, 10:51:32) [MSC v.1944 64 bit (AMD64)]
_WindowsSelectorEventLoop
connection_lost(): called
datagrams received: 5
write buffer size:  0
3.14.7 (tags/v3.14.7:823f032, Aug  5 2026, 10:51:32) [MSC v.1944 64 bit (AMD64)]
ProactorEventLoop
connection_lost(): never called
datagrams received: 1
write buffer size:  72
PS C:\Users\tagra\projects\cpython> py -3.13 .\reproducer.py
3.13.15 (tags/v3.13.15:4061bc4, Aug  5 2026, 13:05:39) [MSC v.1944 64 bit (AMD64)]
_WindowsSelectorEventLoop
connection_lost(): called
datagrams received: 5
write buffer size:  0
3.13.15 (tags/v3.13.15:4061bc4, Aug  5 2026, 13:05:39) [MSC v.1944 64 bit (AMD64)]
ProactorEventLoop
connection_lost(): never called
datagrams received: 1
write buffer size:  72

CPython versions tested on

Py3.13 Py3.14

Operating systems tested on

Windows

CPython versions tested on:

3.13, 3.14

Operating systems tested on:

Windows

Linked PRs

Activity

  1. added a commit that references this issue on Sep 4, 2026
  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Sep 4, 2026
  3. added a commit that references this issue on Sep 16, 2026
  4. moved this from Todo to Done in asyncioon Sep 16, 2026
  5. added a commit that references this issue on Sep 29, 2026
  6. added 2 commits that reference this issue on Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    OS-windowsstdlibStandard Library Python modules in the Lib/ directorytopic-asynciotype-bugAn unexpected behavior, bug, or error

    Projects

    • Status
      Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions