diff --git a/api/services/dataset_service.py b/api/services/dataset_service.py index 880166890e3..a8b83b78047 100644 --- a/api/services/dataset_service.py +++ b/api/services/dataset_service.py @@ -739,8 +739,13 @@ class DatasetService: dataset.id, external_knowledge_id, external_knowledge_api_id, session ) - # Commit changes to database - session.commit() + # Flush changes to the database without closing the caller-managed + # transaction. This helper receives a session opened by the caller + # (`with Session(...) as session`); calling commit() here closed that + # context manager early and raised + # sqlalchemy.exc.InvalidRequestError: Can't operate on closed transaction + # (#39191). + session.flush() return dataset @@ -810,9 +815,15 @@ class DatasetService: if data.get("icon_info"): filtered_data["icon_info"] = data.get("icon_info") - # Update dataset in database + # Update dataset in database. Use flush() rather than commit() so the + # caller-managed transaction (opened with `with Session(...) as session`) + # stays open for subsequent operations — _update_pipeline_knowledge_base + # node data and any caller follow-ups run on the same session. Calling + # commit() here closed the context manager early and raised + # sqlalchemy.exc.InvalidRequestError: Can't operate on closed transaction + # (#39191). session.execute(update(Dataset).where(Dataset.id == dataset.id).values(**filtered_data)) - session.commit() + session.flush() # Reload dataset to get updated values session.refresh(dataset) diff --git a/api/tests/unit_tests/services/test_dataset_service_dataset.py b/api/tests/unit_tests/services/test_dataset_service_dataset.py index 4ce8d46d702..1fcc81039ca 100644 --- a/api/tests/unit_tests/services/test_dataset_service_dataset.py +++ b/api/tests/unit_tests/services/test_dataset_service_dataset.py @@ -631,7 +631,9 @@ class TestDatasetServiceCreationAndUpdate: get_external_knowledge_api.assert_called_once_with("api-1", dataset.tenant_id, session=session) update_binding.assert_called_once_with("dataset-1", "knowledge-1", "api-1", session) session.add.assert_called_once_with(dataset) - session.commit.assert_called_once() + # flush() (not commit()) preserves the caller-managed transaction (#39191) + session.flush.assert_called_once() + session.commit.assert_not_called() @pytest.mark.parametrize( ("payload", "message"), @@ -728,7 +730,9 @@ class TestDatasetServiceCreationAndUpdate: assert "external_knowledge_api_id" not in updated_values assert "external_knowledge_id" not in updated_values assert "external_retrieval_model" not in updated_values - session.commit.assert_called_once() + # flush() (not commit()) preserves the caller-managed transaction (#39191) + session.flush.assert_called_once() + session.commit.assert_not_called() session.refresh.assert_called_once_with(dataset) update_pipeline.assert_called_once_with(dataset, "user-1", session) vector_task.delay.assert_called_once_with("dataset-1", "update")