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:
|
if metadatas is None:
|
||||||
continue
|
continue
|
||||||
metadata = metadatas[i] or {}
|
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(
|
doc = document.Document(
|
||||||
id=metadata.get("doc_id"),
|
id=metadata.get("doc_id"),
|
||||||
vector=embeddings[i],
|
vector=embeddings[i],
|
||||||
|
|||||||
@ -281,6 +281,23 @@ def test_create_add_delete_and_search_behaviour(tencent_module):
|
|||||||
vector._client.drop_collection.assert_called_once()
|
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):
|
def test_tencent_factory_existing_and_generated_collection(tencent_module, monkeypatch: pytest.MonkeyPatch):
|
||||||
factory = tencent_module.TencentVectorFactory()
|
factory = tencent_module.TencentVectorFactory()
|
||||||
dataset_with_index = Dataset(
|
dataset_with_index = Dataset(
|
||||||
|
|||||||
@ -517,8 +517,16 @@ class SummaryIndexService:
|
|||||||
summary_record_id,
|
summary_record_id,
|
||||||
original_session is not None,
|
original_session is not None,
|
||||||
)
|
)
|
||||||
# Always create a new session for error handling to avoid issues with closed sessions
|
if original_session is not None:
|
||||||
# Even if original_session was provided, we create a new one for safety
|
# 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:
|
with session_factory.create_session() as error_session:
|
||||||
# Try to find the record by id first
|
# Try to find the record by id first
|
||||||
# Note: Using assignment only (no type annotation) to avoid redeclaration error
|
# 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()
|
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:
|
def test_batch_create_summary_records_no_segments_noop(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
create_session_mock = MagicMock()
|
create_session_mock = MagicMock()
|
||||||
monkeypatch.setattr(summary_module, "session_factory", SimpleNamespace(create_session=create_session_mock))
|
monkeypatch.setattr(summary_module, "session_factory", SimpleNamespace(create_session=create_session_mock))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user