Skip to content

asyncio.wait leaks completed tasks via the 3.14 await-graph when racing a long-lived Future (missing future_discard_from_awaited_by) #152569

Description

@Skn0tt

Bug report

Bug description:

On Python 3.14, asyncio.wait(..., return_when=FIRST_COMPLETED) permanently retains every
completed waiting task when one of the awaited futures is long-lived (never resolves). Each call
registers the waiting task on the long-lived future's await-graph (_asyncio_awaited_by) but never
discards it once the wait returns, so the task is pinned until that future finally resolves — which,
for a "signal" future used as a cancellation/close marker, can mean the lifetime of the process.

This is the same omission already fixed for asyncio.staggered.staggered_race in
gh-129195 (add to awaited_by → must discard), but asyncio.wait still has it.

import asyncio, gc

async def main():
    loop = asyncio.get_running_loop()
    immortal = loop.create_future()  # never resolves (e.g. a connection-close signal)

    def done_tasks():
        gc.collect()
        return sum(1 for o in gc.get_objects() if isinstance(o, asyncio.Task) and o.done())

    async def race_once():
        await asyncio.wait(
            {asyncio.ensure_future(asyncio.sleep(0)), immortal},
            return_when=asyncio.FIRST_COMPLETED,
        )

    base = done_tasks()
    for _ in range(1000):
        await asyncio.create_task(race_once())
    print("retained done tasks:", done_tasks() - base)
    immortal.cancel()

asyncio.run(main())
3.13: retained done tasks: 1
3.14: retained done tasks: 1000   # grows linearly with calls; freed only when `immortal` resolves

Related

CPython versions tested on:

CPython main branch, 3.14

Operating systems tested on:

macOS

Linked PRs

Activity

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

    3.14bugs and security fixes3.15pre-release feature fixes, bugs and security fixes3.16new features, bugs and security fixesstdlibStandard 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