Merge pull request #730: cap Zep edge pagination safely

Add a bounded edge paginator while preserving the existing positional retry API.
This commit is contained in:
BaiFu 2026-07-22 19:43:11 +08:00 committed by GitHub
commit ce616b05f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 51 additions and 1 deletions

View File

@ -19,6 +19,7 @@ logger = get_logger('mirofish.zep_paging')
_DEFAULT_PAGE_SIZE = 100
_MAX_NODES = 2000
_MAX_EDGES = 5000
_DEFAULT_MAX_RETRIES = 3
_DEFAULT_RETRY_DELAY = 2.0 # seconds, doubles each retry
@ -108,8 +109,9 @@ def fetch_all_edges(
page_size: int = _DEFAULT_PAGE_SIZE,
max_retries: int = _DEFAULT_MAX_RETRIES,
retry_delay: float = _DEFAULT_RETRY_DELAY,
max_items: int = _MAX_EDGES,
) -> list[Any]:
"""分页获取图谱所有边,返回完整列表。每页请求自带重试。"""
"""分页获取图谱所有边,最多返回 max_items 条(默认 5000。每页请求自带重试。"""
all_edges: list[Any] = []
cursor: str | None = None
page_num = 0
@ -132,6 +134,10 @@ def fetch_all_edges(
break
all_edges.extend(batch)
if len(all_edges) >= max_items:
all_edges = all_edges[:max_items]
logger.warning(f"Edge count reached limit ({max_items}), stopping pagination for graph {graph_id}")
break
if len(batch) < page_size:
break

View File

@ -0,0 +1,44 @@
from types import SimpleNamespace
from app.utils import zep_paging
def _client():
edge_api = SimpleNamespace(get_by_graph_id=lambda *args, **kwargs: [])
return SimpleNamespace(graph=SimpleNamespace(edge=edge_api))
def test_edge_cap_stops_pagination_at_requested_limit(monkeypatch):
pages = [
[SimpleNamespace(uuid_="e1"), SimpleNamespace(uuid_="e2")],
[SimpleNamespace(uuid_="e3"), SimpleNamespace(uuid_="e4")],
]
calls = []
def fake_fetch(*args, **kwargs):
calls.append(kwargs)
return pages[len(calls) - 1]
monkeypatch.setattr(zep_paging, "_fetch_page_with_retry", fake_fetch)
result = zep_paging.fetch_all_edges(_client(), "graph", page_size=2, max_items=3)
assert [edge.uuid_ for edge in result] == ["e1", "e2", "e3"]
assert len(calls) == 2
assert calls[1]["uuid_cursor"] == "e2"
def test_existing_positional_retry_arguments_keep_their_meaning(monkeypatch):
observed = {}
def fake_fetch(*args, **kwargs):
observed.update(kwargs)
return []
monkeypatch.setattr(zep_paging, "_fetch_page_with_retry", fake_fetch)
zep_paging.fetch_all_edges(_client(), "graph", 25, 7, 0.25)
assert observed["limit"] == 25
assert observed["max_retries"] == 7
assert observed["retry_delay"] == 0.25