From 9e41fdc5985ce0dd787bc5c3cfa3b1ac74241500 Mon Sep 17 00:00:00 2001 From: Markus Hilger Date: Mon, 10 Aug 2026 23:18:24 +0200 Subject: [PATCH] Hold the async HTTP handler task until it finishes run_handler scheduled the coroutine that serves an async HTTP request and dropped the returned task. The event loop only keeps a weak reference, so the task could be collected while still pending, leaving the request unanswered and "Task was destroyed but it is pending!" in the log. The session already outlives the request in _asyncsessions, so it holds the task in a set and discards it from a done callback. --- confluent_server/confluent/asynchttp.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/confluent_server/confluent/asynchttp.py b/confluent_server/confluent/asynchttp.py index 76458f8d..b24b5505 100644 --- a/confluent_server/confluent/asynchttp.py +++ b/confluent_server/confluent/asynchttp.py @@ -66,6 +66,7 @@ class AsyncSession(object): self.wshandler = wshandler self.termrelations = [] self.consoles = set([]) + self.handlertasks = set() async def add(self, requestid, rsp): await self.wshandler(messages.AsyncMessage((requestid, rsp))) @@ -107,7 +108,11 @@ async def run_handler(hdlr, req): raise exc.InvalidArgumentException( 'Invalid Session ID or missing request id') cloop = asyncio.get_running_loop() - cloop.create_task(asyncsession.run_handler(hdlr, requestid)) + # The loop only keeps a weak reference, so the session holds the task until + # it finishes, otherwise the request can be collected while still pending + hdlrtask = cloop.create_task(asyncsession.run_handler(hdlr, requestid)) + asyncsession.handlertasks.add(hdlrtask) + hdlrtask.add_done_callback(asyncsession.handlertasks.discard) return requestid