Skip to content

fix(agent-server): bypass lifecycle lock for cached event services - #4596

Closed
jstar0 wants to merge 1 commit into
OpenHands:mainfrom
jstar0:fix/4514-cached-event-service-fast-path
Closed

fix(agent-server): bypass lifecycle lock for cached event services#4596
jstar0 wants to merge 1 commit into
OpenHands:mainfrom
jstar0:fix/4514-cached-event-service-fast-path

Conversation

@jstar0

@jstar0 jstar0 commented Aug 23, 2026

Copy link
Copy Markdown

HUMAN:


AGENT:

Why

ConversationService._get_or_load_event_service waits on the global lifecycle lock even when the requested conversation already has an open in-memory EventService. During a slow persistence/runtime preparation, those waits can consume the server's worker threads and block unrelated event endpoints.

Summary

  • Return an open cached EventService before entering lifecycle serialization or disk hydration.
  • Preserve the existing activity touch used to defer idle eviction.
  • Add a regression test that holds the lifecycle lock and verifies cached access completes immediately.

Issue Number

Fixes #4514

How to Test

  • uv run pytest -q tests/agent_server/test_conversation_service.py -k 'cached_event_service_bypasses_lifecycle_lock or get_event_service or conversation_lifecycle' --maxfail=1
  • uv run pre-commit run --files openhands-agent-server/openhands/agent_server/conversation_service.py tests/agent_server/test_conversation_service.py
  • make build

The focused regression/lifecycle tests pass, and the relevant pre-commit hooks pass: Ruff format/lint, pycodestyle, pyright, import rules, and tool registration. The full conversation/event service files were also run; unrelated workspace/git initialization tests fail in this local outer worktree because pytest temporary paths are detected as Git-backed and therefore use conversation worktrees. The changed code is not involved in those failures.

Video/Screenshots

Not applicable for this backend concurrency fix; the regression is covered by an in-process async test.

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

This is an internal agent-server scheduling change with no REST/WebSocket schema changes. The cached fast path is limited to open in-memory runtimes; closed or uncached conversations retain the existing lifecycle and hydration path.

Co-authored-by: openhands <openhands@all-hands.dev>
@neubig

neubig commented Aug 24, 2026

Copy link
Copy Markdown
Member

This PR is superseded by merged PR #4570, which replaced the global lifecycle lock with per-conversation locking. That broader fix removes the cross-conversation blocking scenario this cached-event-service fast path targeted.

This comment was created by an AI agent (OpenHands) on behalf of the user.

@neubig

neubig commented Aug 24, 2026

Copy link
Copy Markdown
Member

Thank you for the focused investigation and implementation. Closing this PR as superseded by merged PR #4570, which addresses the broader lifecycle-lock problem with per-conversation locking.

This action was performed by an AI agent (OpenHands) on behalf of the user.

@neubig neubig closed this Aug 24, 2026
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.

Lifecycle lock deadlock: thread-pool exhaustion blocks all event loading

2 participants