Skip to content

bug: asyncio.run() inside AgentGraph destructor triggers RuntimeError and leaks connections #146

@bhavyakeerthi3

Description

@bhavyakeerthi3

Bug Description

The AgentGraph destructor (__del__) calls asyncio.run(self.close_pool()). In an asynchronous environment (such as a Chainlit or FastAPI server), if the agent is deleted while an event loop is already running, asyncio.run() raises a RuntimeError: This event loop is already running.

Since the destructor fails mid-execution, the connection pool is never closed, leading to hanging database connections and potential pool exhaustion in long-running deployments.

Minimal Reproduction

import asyncio
from agent.graph import AgentGraph

async def reproduce():
    graph = AgentGraph(profiles=["react_to_me"])
    await graph.initialize()
    del graph  # Triggers __del__ while loop is running
    # Result: RuntimeError and postgres connection remains open

asyncio.run(reproduce())

Why It's Non-Obvious

Python's __del__ is called by the garbage collector with no awareness of the async context. There is no exception raised at the call site — the RuntimeError appears only in logs, making this invisible during development and only visible under production load when connection counts begin climbing.

Fix

Update the destructor to be loop-aware:

def __del__(self) -> None:
    if self.pool:
        try:
            loop = asyncio.get_running_loop()
            if loop.is_running():
                loop.create_task(self.close_pool())
            else:
                asyncio.run(self.close_pool())
        except RuntimeError:
            asyncio.run(self.close_pool())

Note: loop.create_task() during __del__ is best-effort —
if the event loop closes before the task executes, cleanup may
still be skipped. The robust long-term solution is explicit
lifecycle management via a shutdown() method called by the
application, rather than relying on __del__ at all.

Files Affected

  • src/agent/graph.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions