Skip to content

fix(memory/honcho): align shutdown join timeout with Honcho HTTP timeout - #33701

Open
Pluviobyte wants to merge 1 commit into
NousResearch:mainfrom
Pluviobyte:fix/honcho-shutdown-join
Open

fix(memory/honcho): align shutdown join timeout with Honcho HTTP timeout#33701
Pluviobyte wants to merge 1 commit into
NousResearch:mainfrom
Pluviobyte:fix/honcho-shutdown-join

Conversation

@Pluviobyte

Copy link
Copy Markdown
Contributor

What does this PR do?

HonchoMemoryProvider.shutdown joined the dialectic / prefetch daemon threads with a fixed timeout=5.0, but the Honcho SDK HTTP client defaults to a 30s timeout (configurable via HonchoClientConfig.timeout, honcho.timeout / requestTimeout, or HONCHO_TIMEOUT). When the join expired before a pending HTTP call returned, the daemon thread was still mid-call once CPython entered Py_FinalizeEx, intermittently aborting the interpreter with SIGABRT during otherwise-clean shutdown. Issue #33485 isolated this to recallMode: hybrid where the dialectic background worker is the most reliable trigger; the reporter confirmed extending the join window to 30s or shrinking the HTTP timeout to 3s eliminates the abort, which matches the timing analysis.

This PR aligns the shutdown grace period with whatever timeout the Honcho client is actually using, while preserving a 5s floor:

  • Extracts the existing timeout-resolution chain inside get_honcho_client into a reusable resolve_http_timeout(config) helper so shutdown and the SDK kwargs read from the same source.
  • Switches HonchoMemoryProvider.shutdown to t.join(timeout=max(5.0, resolve_http_timeout(self._config))) for both _prefetch_thread and _sync_thread. The 5s floor preserves the original grace period when a user configures a very short HTTP timeout — the HTTP call cannot outlive that floor anyway, so the join is still bounded.
  • The helper guards import failures and missing config so shutdown stays exception-free.

Related Issue

Fixes #33485

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • plugins/memory/honcho/client.py — added resolve_http_timeout(config) and routed get_honcho_client through it so SDK and shutdown agree on the effective HTTP timeout.
  • plugins/memory/honcho/__init__.pyHonchoMemoryProvider.shutdown now waits max(5.0, resolve_http_timeout(self._config)) before abandoning the dialectic / prefetch threads.
  • tests/honcho_plugin/test_shutdown_join_timeout.py — new file with 10 regression tests covering explicit config timeout, hermes-cli fallback, default 30s, 5s floor, missing config, and resolve_http_timeout chain semantics.
  • scripts/release.py — added this contributor email to AUTHOR_MAP so the contributor-attribution check has a GitHub username for the noreply address.

How to Test

  1. Configure Honcho with recallMode: hybrid (the default) so the dialectic worker is exercised.
  2. Trigger shutdown while a dialectic HTTP call is in flight (e.g. point Honcho at an unreachable backend so the call sits idle until its 30s timeout, then exit the CLI). Before this PR the daemon thread was orphaned after 5s and CPython occasionally aborted with SIGABRT during Py_FinalizeEx. After this PR the join waits the full 30s, the worker exits cleanly, and the interpreter shuts down without abort.
  3. Run the focused regression suite plus surrounding Honcho tests:
uv run --extra dev python -m pytest tests/honcho_plugin/test_shutdown_join_timeout.py -q
uv run --extra dev python -m pytest tests/honcho_plugin/ tests/test_honcho_session_context.py tests/test_honcho_client_config.py tests/agent/test_memory_user_id.py -q
uv run --extra dev ruff check plugins/memory/honcho/__init__.py plugins/memory/honcho/client.py tests/honcho_plugin/test_shutdown_join_timeout.py scripts/release.py
git diff --check

Regression-coverage check: temporarily reverting the __init__.py change makes 3 of the 4 TestShutdownJoinTimeout tests fail (the one that already expects 5s still passes), confirming the new tests pin the bug rather than the fix.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Linux 6.1 (Amazon Linux), Python 3.12 via uv

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

For New Skills

N/A

Screenshots / Logs

$ uv run --extra dev python -m pytest tests/honcho_plugin/test_shutdown_join_timeout.py -q
..........                                                               [100%]
10 passed in 0.37s

$ uv run --extra dev python -m pytest tests/honcho_plugin/ tests/test_honcho_session_context.py tests/test_honcho_client_config.py tests/agent/test_memory_user_id.py -q
346 passed, 4 skipped in 10.33s

$ uv run --extra dev ruff check plugins/memory/honcho/__init__.py plugins/memory/honcho/client.py tests/honcho_plugin/test_shutdown_join_timeout.py scripts/release.py
All checks passed!

Note on overlap: PRs #7627 (close httpx pool), #31664 (route oneshot through HonchoSessionManager.shutdown), and #33543 (os._exit from oneshot to skip finalizers entirely) target the same SIGABRT class from different layers and are independent of this change. None of them adjusts the 5s join timeout, so this PR is complementary regardless of which lands first.

Made with Cursor

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins tool/memory Memory tool and memory providers labels May 28, 2026
HonchoMemoryProvider.shutdown joined the dialectic / prefetch daemon
threads with a fixed timeout=5.0, but Honcho HTTP calls default to a
30s client timeout. When the join expired before the HTTP call
returned, the daemon thread was still mid-call once CPython entered
Py_FinalizeEx, intermittently aborting the interpreter with SIGABRT
during otherwise-clean CLI shutdown (issue NousResearch#33485, hybrid recall mode).

Extract the existing timeout resolution chain from get_honcho_client
into a reusable resolve_http_timeout(config) helper, then use it from
shutdown so the join window grows to match config.timeout / honcho
config / HONCHO_TIMEOUT / _DEFAULT_HTTP_TIMEOUT. A 5s floor preserves
the original grace period for users who configure a very short HTTP
timeout (their HTTP call cannot outlast the floor anyway).

Also map this contributor in scripts/release.py AUTHOR_MAP so the
contributor-attribution check has a username for the noreply email.

Fixes NousResearch#33485

Co-authored-by: Cursor <cursoragent@cursor.com>

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for isolating the fixed 5s-versus-client-timeout mismatch. Current main still has the fixed t.join(timeout=5.0) in plugins/memory/honcho/__init__.py:1414-1417, while its client defaults unresolved HTTP calls to 30s in plugins/memory/honcho/client.py:209-215 and passes that resolved value at client.py:841-862.

Problems

  • tests/honcho_plugin/test_shutdown_join_timeout.py only checks mocked Thread.join arguments and mocked configuration. It does not execute client construction and provider shutdown through one resolved configuration path, so the claimed shared-resolution contract is not covered end to end.

Suggested changes

  • Add an isolated-HERMES_HOME regression that captures the SDK constructor timeout via get_honcho_client and verifies provider shutdown derives the same value without a real 30-second wait.

This is an automated hermes-sweeper review.

provider._sync_thread = sync
provider._manager = None # skip flush_all

provider.shutdown()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This mock-only assertion proves the join argument derived by the helper, but not that SDK construction and shutdown use the same resolution path. Please add an isolated-HERMES_HOME regression that captures the timeout passed by get_honcho_client and verifies shutdown uses that identical value.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform area/memory Memory subsystem: store, providers, sync, background reviews labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/memory Memory subsystem: store, providers, sync, background reviews comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state tool/memory Memory tool and memory providers type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Honcho hybrid memory can leave daemon dialectic threads alive during CLI shutdown, causing intermittent CPython abort

3 participants