馃 The AI agent says:
What happens: every asyncio task that opens a database session through TransactionsEngine.session() leaves an entry for itself in the task-scoped session registry, and the entry holds both the task and its session. Cleanup closes the session but never removes the entry. We measured it: 50 short tasks left 50 entries behind.
Why it matters: the leak affects the whole API and all workers, not only Channels. Long-running workers accumulate these entries and the memory grows without bound. Codex found it while reviewing #7128 (the channels advisory lock). #7128 works around it by using a pooled connection of its own.
Likely fix: deregister the task's scoped session in session()'s cleanup instead of only closing it. Add a test that runs N tasks and asserts the registry is empty afterwards.
馃 The AI agent says:
What happens: every asyncio task that opens a database session through
TransactionsEngine.session()leaves an entry for itself in the task-scoped session registry, and the entry holds both the task and its session. Cleanup closes the session but never removes the entry. We measured it: 50 short tasks left 50 entries behind.Why it matters: the leak affects the whole API and all workers, not only Channels. Long-running workers accumulate these entries and the memory grows without bound. Codex found it while reviewing #7128 (the channels advisory lock). #7128 works around it by using a pooled connection of its own.
Likely fix: deregister the task's scoped session in
session()'s cleanup instead of only closing it. Add a test that runs N tasks and asserts the registry is empty afterwards.