Skip to content

fix: replace asyncio.sleep FAF guards with deterministic awaits#919

Open
ajbozarth wants to merge 3 commits intogenerative-computing:mainfrom
ajbozarth:fix/691-fire-and-forget-sync
Open

fix: replace asyncio.sleep FAF guards with deterministic awaits#919
ajbozarth wants to merge 3 commits intogenerative-computing:mainfrom
ajbozarth:fix/691-fire-and-forget-sync

Conversation

@ajbozarth
Copy link
Copy Markdown
Contributor

Misc PR

Type of PR

  • Bug Fix

Description

Bumps cpex to 0.1.0.dev12, which adds PluginResult.background_tasks and wait_for_background_tasks() (upstream contextforge-org/contextforge-plugins-framework#33). Uses these to replace all racy asyncio.sleep() guards that were used to wait for FIRE_AND_FORGET plugin completion in tests.

Changes:

  • mellea/plugins/manager.py: add drain_background_tasks() — accumulates PluginResult objects with background tasks in invoke_hook(), drains via wait_for_background_tasks() for tests where the hook fires inside a backend call
  • test/plugins/test_execution_modes.py: capture invoke_hook result directly and call result.wait_for_background_tasks() (2 tests)
  • test/telemetry/test_metrics_backend.py: replace 7× asyncio.sleep(0.05) with drain_background_tasks()

Testing

  • Tests added to the respective file if code was changed
  • New code has 100% coverage if code as added
  • Ensure existing tests and github automation passes (a maintainer will kick off the github automation when the rest of the PR is populated)

Attribution

  • AI coding assistants used: Claude Code

Bumps cpex to 0.1.0.dev12, which exposes PluginResult.background_tasks
and wait_for_background_tasks(). Uses these to eliminate all racy
asyncio.sleep() calls that were guarding FIRE_AND_FORGET plugin
completion in tests.

- Add drain_background_tasks() to mellea/plugins/manager.py: accumulates
  PluginResult objects with background tasks in invoke_hook(), drains via
  wait_for_background_tasks() in tests
- test/plugins/test_execution_modes.py: capture invoke_hook result and
  call result.wait_for_background_tasks() directly
- test/telemetry/test_metrics_backend.py: replace 7x asyncio.sleep(0.05)
  with drain_background_tasks()

Closes generative-computing#691

Assisted-by: Claude Code
Signed-off-by: Alex Bozarth <ajbozart@us.ibm.com>
@ajbozarth ajbozarth requested a review from a team as a code owner April 23, 2026 22:00
@github-actions github-actions Bot added the bug Something isn't working label Apr 23, 2026
@ajbozarth ajbozarth self-assigned this Apr 23, 2026
Add discard_background_tasks() to clear accumulated FIRE_AND_FORGET
results without awaiting them, and call it in the enable_metrics fixture
to discard stale results from previous test event loops before each test.

Also clears _pending_background_results in shutdown_plugins() for
completeness.

Assisted-by: Claude Code
Signed-off-by: Alex Bozarth <ajbozart@us.ibm.com>
@ajbozarth
Copy link
Copy Markdown
Contributor Author

Follow-up to address a test failure in test_ollama_token_metrics_integration[non-streaming].

The _pending_background_results global accumulates PluginResult objects across the entire test session. pytest-asyncio creates a new event loop per test, so results from earlier tests hold futures bound to dead loops. When a later test calls drain_background_tasks(), awaiting those stale futures raises RuntimeError: Future attached to a different loop.

Fix: added discard_background_tasks() to manager.py — same as drain_background_tasks but discards without awaiting, safe to call across loop boundaries. The enable_metrics fixture in test_metrics_backend.py now calls it before and after each test to ensure only results from the current event loop are ever drained.

Also clears _pending_background_results in shutdown_plugins() for completeness.

@ajbozarth ajbozarth closed this Apr 24, 2026
@ajbozarth ajbozarth deleted the fix/691-fire-and-forget-sync branch April 24, 2026 17:46
@ajbozarth ajbozarth restored the fix/691-fire-and-forget-sync branch April 24, 2026 17:46
@ajbozarth ajbozarth reopened this Apr 24, 2026
@ajbozarth
Copy link
Copy Markdown
Contributor Author

Claude decided to delete my worktree for this PR instead of #895 when I went to clean up and I didn't noticed it picked the wrong branch name

@ajbozarth
Copy link
Copy Markdown
Contributor Author

cc @araujof as the original plugins/hook author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide a deterministic way to await FIRE_AND_FORGET hook completion in tests

1 participant