fix(api): report checkpoint deletion failures and classify SSE errors
Delete checkpoints before removing business fields. Suppress only an explicit CheckpointNotFoundError; propagate storage failures and cancellation so the endpoint cannot report false success. Prefer async checkpoint deletion and fail clearly when cleanup is unsupported. Classify SSE error events as 401 for authentication, 429 for rate limits, and 500 for other failures, using the same fixed messages as non-stream responses. Errors terminate the stream without a success done event or provider exception text in the response. Validation: 286 offline tests passed (19 added), including failed-delete HTTP retry with preserved business/checkpoint state, explicit missing threads, cancellation, missing cleanup capability, and HTTP SSE errors before and after text output.
This commit is contained in:
@@ -104,3 +104,43 @@ def test_assignment6_acceptance_flow(client):
|
||||
"text": "新对话", "clientMode": "direct",
|
||||
})
|
||||
assert response.json()["code"] == "200"
|
||||
|
||||
|
||||
def test_delete_checkpoint_failure_returns_error_and_retry_cleans_session(client, monkeypatch):
|
||||
from unittest.mock import AsyncMock
|
||||
from src.core import fastgpt_client as wiring
|
||||
|
||||
session = "delete-retry"
|
||||
payload = {"sessionId": session, "timeStamp": TS}
|
||||
assert client.post("/set_info", json={
|
||||
**payload, "key": "hphm1", "value": "test-plate",
|
||||
}).json()["code"] == "200"
|
||||
assert client.post("/chat", json={
|
||||
**payload, "text": "新对话",
|
||||
}).json()["nextStageCode"] == "1001"
|
||||
saver = wiring._langgraph_graph.checkpointer
|
||||
config = {"configurable": {"thread_id": session}}
|
||||
assert saver.get_tuple(config) is not None
|
||||
original_delete = saver.adelete_thread
|
||||
failing_delete = AsyncMock(side_effect=ConnectionError("private storage detail"))
|
||||
monkeypatch.setattr(saver, "adelete_thread", failing_delete)
|
||||
|
||||
response = client.request("DELETE", "/delete_session", json=payload)
|
||||
assert response.json()["code"] == "500"
|
||||
assert response.json()["msg"] == "删除会话失败"
|
||||
assert "private storage detail" not in response.text
|
||||
failing_delete.assert_awaited_once_with(session)
|
||||
assert saver.get_tuple(config) is not None
|
||||
assert json.loads(client.post("/get_info", json={
|
||||
**payload, "key": "hphm1",
|
||||
}).json()["value"]) == "test-plate"
|
||||
|
||||
monkeypatch.setattr(saver, "adelete_thread", original_delete)
|
||||
assert client.request("DELETE", "/delete_session", json=payload).json()["code"] == "200"
|
||||
assert saver.get_tuple(config) is None
|
||||
assert json.loads(client.post("/get_info", json={
|
||||
**payload, "key": "hphm1",
|
||||
}).json()["value"]) == ""
|
||||
assert client.post("/chat", json={
|
||||
**payload, "text": "新对话",
|
||||
}).json()["nextStageCode"] == "1001"
|
||||
|
||||
Reference in New Issue
Block a user