mirror of
https://github.com/langgenius/dify.git
synced 2026-09-08 11:04:27 +08:00
fix(api): fix tencent summary vector deadlock (#41916)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
eba589db89
commit
60656a60cf
@ -202,6 +202,11 @@ class TencentVector(BaseVector):
|
||||
if metadatas is None:
|
||||
continue
|
||||
metadata = metadatas[i] or {}
|
||||
if metadata.get("is_summary") is True:
|
||||
# Tencent VectorDB JSON fields do not support boolean values.
|
||||
# Use an integer only for the summary marker so other metadata
|
||||
# and other vector backends keep their existing types.
|
||||
metadata = {**metadata, "is_summary": 1}
|
||||
doc = document.Document(
|
||||
id=metadata.get("doc_id"),
|
||||
vector=embeddings[i],
|
||||
|
||||
@ -281,6 +281,23 @@ def test_create_add_delete_and_search_behaviour(tencent_module):
|
||||
vector._client.drop_collection.assert_called_once()
|
||||
|
||||
|
||||
def test_add_texts_converts_only_true_summary_marker(tencent_module):
|
||||
vector = tencent_module.TencentVector("collection_1", _config(tencent_module))
|
||||
summary_metadata = {"doc_id": "summary", "is_summary": True, "published": False}
|
||||
regular_metadata = {"doc_id": "regular", "published": False}
|
||||
docs = [
|
||||
Document(page_content="summary", metadata=summary_metadata),
|
||||
Document(page_content="regular", metadata=regular_metadata),
|
||||
]
|
||||
|
||||
vector.add_texts(docs, [[0.1], [0.2]])
|
||||
|
||||
upserted = vector._client.upsert.call_args.kwargs["documents"]
|
||||
assert upserted[0].metadata == {"doc_id": "summary", "is_summary": 1, "published": False}
|
||||
assert upserted[1].metadata == regular_metadata
|
||||
assert summary_metadata["is_summary"] is True
|
||||
|
||||
|
||||
def test_tencent_factory_existing_and_generated_collection(tencent_module, monkeypatch: pytest.MonkeyPatch):
|
||||
factory = tencent_module.TencentVectorFactory()
|
||||
dataset_with_index = Dataset(
|
||||
|
||||
@ -517,8 +517,16 @@ class SummaryIndexService:
|
||||
summary_record_id,
|
||||
original_session is not None,
|
||||
)
|
||||
# Always create a new session for error handling to avoid issues with closed sessions
|
||||
# Even if original_session was provided, we create a new one for safety
|
||||
if original_session is not None:
|
||||
# Keep the error update in the caller-owned transaction. Opening another
|
||||
# session here can deadlock when the caller has already flushed this row.
|
||||
summary_record.status = SummaryStatus.ERROR
|
||||
summary_record.error = f"Vectorization failed: {str(e)}"
|
||||
summary_record.updated_at = datetime.now(UTC).replace(tzinfo=None)
|
||||
original_session.add(summary_record)
|
||||
raise
|
||||
|
||||
# Standalone callers still need this method to persist the error itself.
|
||||
with session_factory.create_session() as error_session:
|
||||
# Try to find the record by id first
|
||||
# Note: Using assignment only (no type annotation) to avoid redeclaration error
|
||||
|
||||
@ -281,6 +281,45 @@ def test_vectorize_summary_final_failure_updates_error_status(monkeypatch: pytes
|
||||
error_session.commit.assert_called_once()
|
||||
|
||||
|
||||
def test_vectorize_summary_failure_with_provided_session_does_not_open_error_session(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
dataset = _dataset()
|
||||
segment = _segment()
|
||||
summary = _summary_record(summary_content="sum", node_id=None)
|
||||
|
||||
monkeypatch.setattr(summary_module.uuid, "uuid4", MagicMock(return_value="uuid-1"))
|
||||
monkeypatch.setattr(summary_module.helper, "generate_text_hash", MagicMock(return_value="hash-1"))
|
||||
monkeypatch.setattr(
|
||||
summary_module,
|
||||
"Vector",
|
||||
MagicMock(return_value=MagicMock(add_texts=MagicMock(side_effect=RuntimeError("boom")))),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
summary_module.ModelManager,
|
||||
"for_tenant",
|
||||
MagicMock(return_value=MagicMock(get_model_instance=MagicMock(return_value=None))),
|
||||
)
|
||||
|
||||
session = MagicMock(name="provided_session")
|
||||
create_session_mock = MagicMock()
|
||||
monkeypatch.setattr(
|
||||
summary_module,
|
||||
"session_factory",
|
||||
SimpleNamespace(create_session=create_session_mock),
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError, match="boom"):
|
||||
SummaryIndexService.vectorize_summary(summary, segment, dataset, session=session)
|
||||
|
||||
create_session_mock.assert_not_called()
|
||||
session.add.assert_called_once_with(summary)
|
||||
session.commit.assert_not_called()
|
||||
session.flush.assert_not_called()
|
||||
assert summary.status == SummaryStatus.ERROR
|
||||
assert summary.error == "Vectorization failed: boom"
|
||||
|
||||
|
||||
def test_batch_create_summary_records_no_segments_noop(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
create_session_mock = MagicMock()
|
||||
monkeypatch.setattr(summary_module, "session_factory", SimpleNamespace(create_session=create_session_mock))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user