From df67ae730b818086d507104a686e92a355be9bdf Mon Sep 17 00:00:00 2001 From: Teknium Date: Sat, 21 Mar 2026 07:20:58 -0700 Subject: [PATCH] fix(cron): close abandoned coroutine when asyncio.run() raises RuntimeError Cherry-picked from PR #2290 by @Mibayy. Closes #2138. When asyncio.run() raises RuntimeError (running loop exists), the coroutine was created but never awaited, producing a RuntimeWarning on GC. Extract coro before try, call coro.close() in the except branch before falling back to ThreadPoolExecutor. --- cron/scheduler.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cron/scheduler.py b/cron/scheduler.py index e08eaa0da..3108ff3ad 100644 --- a/cron/scheduler.py +++ b/cron/scheduler.py @@ -170,11 +170,15 @@ def _deliver_result(job: dict, content: str) -> None: ) # Run the async send in a fresh event loop (safe from any thread) + coro = _send_to_platform(platform, pconfig, chat_id, wrapped, thread_id=thread_id) try: - result = asyncio.run(_send_to_platform(platform, pconfig, chat_id, wrapped, thread_id=thread_id)) + result = asyncio.run(coro) except RuntimeError: - # asyncio.run() fails if there's already a running loop in this thread; - # spin up a new thread to avoid that. + # asyncio.run() checks for a running loop before awaiting the coroutine; + # when it raises, the original coro was never started — close it to + # prevent "coroutine was never awaited" RuntimeWarning, then retry in a + # fresh thread that has no running loop. + coro.close() import concurrent.futures with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool: future = pool.submit(asyncio.run, _send_to_platform(platform, pconfig, chat_id, wrapped, thread_id=thread_id))