Skip to content

fix: use per-thread persistent event loops in worker threads#2214

Merged
teknium1 merged 1 commit into
mainfrom
fix/event-loop-closed-delegate
Mar 20, 2026
Merged

fix: use per-thread persistent event loops in worker threads#2214
teknium1 merged 1 commit into
mainfrom
fix/event-loop-closed-delegate

Conversation

@jquesnelle

@jquesnelle jquesnelle commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Replace asyncio.run() with thread-local persistent event loops for worker threads (e.g., delegate_task's ThreadPoolExecutor). asyncio.run() creates and closes a fresh loop on every call, leaving cached httpx/AsyncOpenAI clients bound to a dead loop — causing 'Event loop is closed' errors during GC when parallel subagents clean up connections.

The fix mirrors the main thread's _get_tool_loop() pattern but uses threading.local() so each worker thread gets its own long-lived loop, avoiding both cross-thread contention and the create-destroy lifecycle.

Added 4 regression tests covering worker loop persistence, reuse, per-thread isolation, and separation from the main thread's loop.

Replace asyncio.run() with thread-local persistent event loops for
worker threads (e.g., delegate_task's ThreadPoolExecutor). asyncio.run()
creates and closes a fresh loop on every call, leaving cached
httpx/AsyncOpenAI clients bound to a dead loop — causing 'Event loop is
closed' errors during GC when parallel subagents clean up connections.

The fix mirrors the main thread's _get_tool_loop() pattern but uses
threading.local() so each worker thread gets its own long-lived loop,
avoiding both cross-thread contention and the create-destroy lifecycle.

Added 4 regression tests covering worker loop persistence, reuse,
per-thread isolation, and separation from the main thread's loop.
@teknium1 teknium1 merged commit ba0b77a into main Mar 20, 2026
1 check passed
angelburgosrosado pushed a commit to angelburgosrosado/hermes-agent that referenced this pull request Apr 27, 2026
…-closed-delegate

Completes the event loop lifecycle fix trilogy (NousResearch#2190NousResearch#2207NousResearch#2214). Per-thread persistent loops for worker threads prevent GC crashes on cached async clients.
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
…-closed-delegate

Completes the event loop lifecycle fix trilogy (NousResearch#2190NousResearch#2207NousResearch#2214). Per-thread persistent loops for worker threads prevent GC crashes on cached async clients.
olympus-terminal pushed a commit to olympus-terminal/hermes-agent that referenced this pull request May 16, 2026
…-closed-delegate

Completes the event loop lifecycle fix trilogy (NousResearch#2190NousResearch#2207NousResearch#2214). Per-thread persistent loops for worker threads prevent GC crashes on cached async clients.
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
…-closed-delegate

Completes the event loop lifecycle fix trilogy (NousResearch#2190NousResearch#2207NousResearch#2214). Per-thread persistent loops for worker threads prevent GC crashes on cached async clients.
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
…-closed-delegate

Completes the event loop lifecycle fix trilogy (NousResearch#2190NousResearch#2207NousResearch#2214). Per-thread persistent loops for worker threads prevent GC crashes on cached async clients.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants