Skip to content

Fix: Allow running in environments with existing event loop#222

Open
zhenliemao wants to merge 7 commits into
NVIDIA:mainfrom
zhenliemao:fix-running-loop-detection
Open

Fix: Allow running in environments with existing event loop#222
zhenliemao wants to merge 7 commits into
NVIDIA:mainfrom
zhenliemao:fix-running-loop-detection

Conversation

@zhenliemao

@zhenliemao zhenliemao commented Jun 28, 2026

Copy link
Copy Markdown

Summary:
This fix allows SkillSpector to run in environments that already have a running event loop, preventing RuntimeError when asyncio.run() is called from within an existing loop.

Problem:
When running SkillSpector in environments like:

  • Jupyter Notebooks
  • LangGraph Studio
  • FastAPI applications
  • Any programmatic usage within async code The call to asyncio.run() throws a RuntimeError: This event loop is already running and falls back to unfiltered static findings, silently disabling LLM analysis. The previous approach of detecting this state via error message substring matching is fragile and locale-dependent.

Solution:

  1. Add utility function in that properly detects running loops using
  2. When no running loop exists, fall back to directly
  3. When a loop is already running, offload execution to a separate thread with its own event loop via
  4. Replace all calls across all analyzer nodes with the new helper
  5. Remove unused asyncio imports from analyzer files

Test:
Add comprehensive unit tests for run_async covering:

Summary:
This fix allows SkillSpector to run in environments that already have a running event loop, preventing RuntimeError when asyncio.run() is called from within an existing loop.

Problem:
When running SkillSpector in environments like:
- Jupyter Notebooks
- LangGraph Studio
- FastAPI applications
- Any programmatic usage within async code
The call to asyncio.run() throws a RuntimeError: This event loop is already running and falls back to unfiltered static findings, silently disabling LLM analysis. The previous approach of detecting this state via error message substring matching is fragile and locale-dependent.

Solution:
1. Add  utility function in  that properly detects running loops using
2. When no running loop exists, fall back to  directly
3. When a loop is already running, offload execution to a separate thread with its own event loop via
4. Replace all  calls across all analyzer nodes with the new  helper
5. Remove unused asyncio imports from analyzer files

Test:
Add comprehensive unit tests for run_async covering:
- Normal execution without existing running loop
- Nested execution inside an already running loop
- Exception propagation from async coroutines
- Correct handling of async functions with await calls

Signed-off-by: zhenliemao <494822673@qq.com>
Signed-off-by: zhenliemao <494822673@qq.com>

@rng1995 rng1995 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The helper is a reasonable approach, but two blockers remain: the behavior that prevents nested asyncio.run failures has no test coverage, and current head conflicts with main in src/skillspector/llm_utils.py. Please rebase and resolve the conflict, then add focused running-loop tests before merge.

except RuntimeError:
return asyncio.run(coroutine)

with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the core behavior the PR exists to change, but no test exercises either branch. Add regressions that call run_async outside an event loop and from within a running loop, and assert both successful results and exception propagation.

Signed-off-by: zhenliemao <494822673@qq.com>
@zhenliemao zhenliemao requested a review from rng1995 July 1, 2026 07:02

@rng1995 rng1995 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Automated SkillSpector Review]

Re-review: still requesting changes. The prior behavioral-test gap is resolved and the merge conflict is gone: the new tests cover both event-loop branches and exception propagation. Current head nevertheless fails every Python CI job because the changed import block fails ruff I001; the merge commit also fails DCO. Run ruff check/format, sign off all PR commits, and restore green checks.

import concurrent.futures
from collections.abc import Coroutine
from typing import Any
import json

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: this import block is unsorted (json appears after typing imports), and all Python CI jobs stop at ruff I001 here. Organize the imports and run both ruff check and ruff format --check over src/ and tests/; the newly added test class also needs formatter cleanup.

@zhenliemao zhenliemao force-pushed the fix-running-loop-detection branch from d4bc2bc to 7eefd67 Compare July 11, 2026 14:54
Signed-off-by: zhenliemao <494822673@qq.com>
Signed-off-by: zhenliemao <494822673@qq.com>
Signed-off-by: zhenliemao <494822673@qq.com>
@zhenliemao zhenliemao force-pushed the fix-running-loop-detection branch from 916cc94 to 24cfc13 Compare July 11, 2026 15:41
@zhenliemao zhenliemao requested a review from rng1995 July 11, 2026 15:42
@zhenliemao

Copy link
Copy Markdown
Author

i have pushed new commits that resolved the DCO problems, ruff check and conflict

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.

[BUG] RuntimeError: asyncio.run() called from within an already running event loop

2 participants