Files
Hy-Memory/tests/test_client_loop_lifecycle.py
T
3370a715dd fix(client): stop both owned event loops on close (#91)
A solo client creates a write loop and a separate search loop, but close()
stopped only the write loop and __aexit__ stopped neither. Every client
instance against a long-lived process therefore leaked the search thread,
its selector and its 50ms self-wakeup timer. _LoopThread.stop() also left
the loop object unclosed.

Stop every owned loop from one idempotent helper used by both close() and
__aexit__, leave shared-runtime loops to the runtime, and close the loop
after its thread exits. Add lifecycle regressions for both modes.

Co-authored-by: qiye.sjh <shijiahao_0802@youzan.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-10-21 12:19:38 +08:00

46 lines
1.3 KiB
Python

# -*- coding: utf-8 -*-
"""Owned event-loop threads must be stopped and closed with the client."""
from hy_memory.client import HyMemoryClient, _LoopThread
def test_loop_thread_stop_closes_the_loop_and_is_idempotent():
loop_thread = _LoopThread()
loop = loop_thread._loop
loop_thread.stop()
assert not loop_thread._thread.is_alive()
assert loop.is_closed()
# A second stop must not touch a closed loop.
loop_thread.stop()
def test_close_stops_both_loops_owned_by_a_solo_client():
client = HyMemoryClient.__new__(HyMemoryClient)
client._registry = None
client._owns_runtime = True
client._loop_thread = _LoopThread()
client._search_loop_thread = _LoopThread()
loops = [client._loop_thread._loop, client._search_loop_thread._loop]
client.close()
assert all(loop.is_closed() for loop in loops)
def test_shared_runtime_loops_are_left_to_the_runtime():
client = HyMemoryClient.__new__(HyMemoryClient)
client._registry = None
client._owns_runtime = False
client._loop_thread = _LoopThread()
client._search_loop_thread = _LoopThread()
loops = [client._loop_thread._loop, client._search_loop_thread._loop]
try:
client.close()
assert all(not loop.is_closed() for loop in loops)
finally:
client._loop_thread.stop()
client._search_loop_thread.stop()