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>
46 lines
1.3 KiB
Python
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()
|