Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:OpenHands OpenHands ClusteredConversationManager Close Session

From Leeroopedia
Knowledge Sources
Domains Distributed_Systems, Conversation_Management
Last Updated 2026-02-11 21:00 GMT

Overview

Concrete tool for gracefully closing agent sessions with distributed cleanup across cluster nodes, provided by the OpenHands enterprise conversation management layer.

Description

The close_session method in ClusteredConversationManager orchestrates the graceful termination of a conversation session. It stops the agent loop, publishes a closure notification to all cluster nodes via Redis pub/sub, destroys the runtime container, releases the distributed lock, and removes the conversation from the local state cache.

The implementation is supported by two companion housekeeping methods:

  • _disconnect_from_stopped -- Periodically scans the local state cache for conversations whose agent loops have stopped (either by completion or error) but whose sessions have not yet been formally closed. It marks these conversations as disconnected and initiates cleanup after a grace period.
  • _close_disconnected -- Scans for sessions that have been in a disconnected state longer than the configured grace period and closes them. This handles scenarios where a user navigates away without explicitly closing the conversation, or where a network partition separates the WebSocket client from the server.

The SaasNestedConversationManager also provides its own close_session implementation (at L625-644) that additionally handles nested runtime-specific teardown: it sends a shutdown request to the nested server's API before destroying the container, ensuring the inner server can flush its state.

Usage

close_session is called when a conversation ends for any reason: user-initiated close, agent completion, timeout, or error. The housekeeping methods _disconnect_from_stopped and _close_disconnected are run periodically as background tasks (typically every few seconds) to catch orphaned sessions.

Code Reference

Source Location

  • Repository: OpenHands
  • File: enterprise/server/clustered_conversation_manager.py
  • Lines: L380-387 (close_session), L485-543 (_disconnect_from_stopped), L545-581 (_close_disconnected)
  • Also: enterprise/server/saas_nested_conversation_manager.py L625-644 (SaasNestedConversationManager.close_session)

Signature

async def close_session(self, sid: str) -> None
async def _disconnect_from_stopped(self) -> None
async def _close_disconnected(self) -> None

Import

from enterprise.server.clustered_conversation_manager import ClusteredConversationManager

I/O Contract

Inputs

Name Type Required Description
sid str Yes The unique session/conversation identifier to close. Used to look up the conversation in the local state cache, release its distributed lock, and publish the closure notification.

For _disconnect_from_stopped and _close_disconnected:

Name Type Required Description
(self) ClusteredConversationManager Yes The manager instance containing the local state cache, Redis connection, and configuration for grace periods and timeouts.

Outputs

Name Type Description
(side effect) None close_session stops the agent loop, publishes a Redis notification, destroys the runtime, releases the lock, and removes the conversation from local state. _disconnect_from_stopped marks stopped conversations as disconnected. _close_disconnected closes sessions that have exceeded the grace period. All methods return None.

Usage Examples

Basic Usage

from enterprise.server.clustered_conversation_manager import ClusteredConversationManager

manager: ClusteredConversationManager = ...

# Close a specific session
await manager.close_session(sid="conv_abc123")
# The conversation is now stopped, other nodes are notified,
# and all resources are released.

Periodic Housekeeping

import asyncio

async def housekeeping_loop(manager: ClusteredConversationManager):
    """Background task that periodically cleans up orphaned sessions."""
    while True:
        # Detect conversations whose agent loops have stopped
        await manager._disconnect_from_stopped()

        # Close sessions that have been disconnected past the grace period
        await manager._close_disconnected()

        await asyncio.sleep(5)  # Run every 5 seconds

# Start as a background task
housekeeping_task = asyncio.create_task(housekeeping_loop(manager))

SaasNested Variant

from enterprise.server.saas_nested_conversation_manager import SaasNestedConversationManager

nested_manager: SaasNestedConversationManager = ...

# The SaasNested variant additionally sends a shutdown request
# to the nested server before destroying the container
await nested_manager.close_session(sid="conv_abc123")

Related Pages

Implements Principle

Environment

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment