fix(dataset): block dataset deletion while documents are actively indexing - #38667
Open
manan-tech wants to merge 2 commits into
Open
fix(dataset): block dataset deletion while documents are actively indexing#38667manan-tech wants to merge 2 commits into
manan-tech wants to merge 2 commits into
Conversation
…exing Deleting a dataset while its documents are mid-indexing races the in-flight indexing pipeline against `clean_dataset_task`, leaving orphaned document_segments, child_chunks and vector collections (langgenius#38518). `DatasetService.delete_dataset` now raises `DatasetIndexingInProgressError`, mapped to HTTP 409 on both the console and service API delete endpoints, when any document of the dataset is in an in-flight indexing status (parsing/cleaning/splitting/indexing) and not paused. Paused documents do not block deletion, so pausing stays the escape hatch for stuck indexing runs. WAITING documents do not block either: their queued task no-ops once the dataset rows are gone, and the console offers no pause control for queued documents. Fixes langgenius#38522
manan-tech
requested review from
JohnJyong,
QuantumGhost and
laipz8200
as code owners
July 10, 2026 12:56
Contributor
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-07-10 13:00:52.768681388 +0000
+++ /tmp/pyrefly_pr.txt 2026-07-10 13:00:43.786640538 +0000
@@ -7251,7 +7251,7 @@
ERROR Argument `scoped_session[flask_sqlalchemy.session.Session]` is not assignable to parameter `session` with type `sqlalchemy.orm.session.Session` in function `services.data_migration.import_service.MigrationImportService.import_package` [bad-argument-type]
--> tests/unit_tests/services/data_migration/test_import_service.py:999:49
ERROR Argument `str` is not assignable to parameter `indexing_technique` with type `Literal['economy', 'high_quality']` in function `services.entities.knowledge_entities.rag_pipeline_entities.KnowledgeConfiguration.__init__` [bad-argument-type]
- --> tests/unit_tests/services/dataset_service_test_helpers.py:447:28
+ --> tests/unit_tests/services/dataset_service_test_helpers.py:448:28
ERROR Unexpected keyword argument `workspace_id` in function `services.enterprise.enterprise_service.DefaultWorkspaceJoinResult.__init__` [unexpected-keyword]
--> tests/unit_tests/services/enterprise/test_enterprise_service.py:264:40
ERROR Unexpected keyword argument `workspace_id` in function `services.enterprise.enterprise_service.DefaultWorkspaceJoinResult.__init__` [unexpected-keyword]
@@ -7545,35 +7545,35 @@
ERROR Object of class `FromClause` has no attribute `create` [missing-attribute]
--> tests/unit_tests/services/test_credit_pool_service.py:144:5
ERROR Argument `SimpleNamespace` is not assignable to parameter `account` with type `Account` in function `services.dataset_service.DatasetService.create_empty_dataset` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:348:61
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:349:61
ERROR Argument `SimpleNamespace` is not assignable to parameter `account` with type `Account` in function `services.dataset_service.DatasetService.create_empty_dataset` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:373:25
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:374:25
ERROR Argument `SimpleNamespace` is not assignable to parameter `account` with type `Account` in function `services.dataset_service.DatasetService.create_empty_dataset` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:417:25
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:418:25
ERROR Argument `SimpleNamespace` is not assignable to parameter `dataset` with type `Dataset` in function `services.dataset_service.DatasetService._update_pipeline_knowledge_base_node_data` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:728:70
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:729:70
ERROR Argument `SimpleNamespace` is not assignable to parameter `dataset` with type `Dataset` in function `services.dataset_service.DatasetService._update_pipeline_knowledge_base_node_data` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:738:70
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:739:70
ERROR Argument `SimpleNamespace` is not assignable to parameter `dataset` with type `Dataset` in function `services.dataset_service.DatasetService._update_pipeline_knowledge_base_node_data` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:777:70
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:778:70
ERROR Argument `SimpleNamespace` is not assignable to parameter `dataset` with type `Dataset` in function `services.dataset_service.DatasetService._update_pipeline_knowledge_base_node_data` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:800:74
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:801:74
ERROR Object of class `FakeAccount` has no attribute `current_tenant_id` [missing-attribute]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:879:9
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:880:9
ERROR Object of class `FakeAccount` has no attribute `current_tenant_id` [missing-attribute]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:919:9
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:920:9
ERROR Argument `None` is not assignable to parameter `embedding_model_provider` with type `str` in function `tests.unit_tests.services.dataset_service_test_helpers.DatasetServiceUnitDataFactory.create_dataset_mock` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:996:38
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:997:38
ERROR Argument `None` is not assignable to parameter `embedding_model` with type `str` in function `tests.unit_tests.services.dataset_service_test_helpers.DatasetServiceUnitDataFactory.create_dataset_mock` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:997:29
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:998:29
ERROR Object of class `FakeAccount` has no attribute `current_tenant_id` [missing-attribute]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:1066:9
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:1067:9
ERROR Object of class `FakeAccount` has no attribute `current_tenant_id` [missing-attribute]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:1103:9
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:1104:9
ERROR Argument `SimpleNamespace` is not assignable to parameter `user` with type `Account | None` in function `services.dataset_service.DatasetService.check_dataset_operator_permission` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:1401:22
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:1402:22
ERROR Argument `SimpleNamespace` is not assignable to parameter `dataset` with type `Dataset | None` in function `services.dataset_service.DatasetService.check_dataset_operator_permission` [bad-argument-type]
- --> tests/unit_tests/services/test_dataset_service_dataset.py:1409:25
+ --> tests/unit_tests/services/test_dataset_service_dataset.py:1410:25
ERROR Object of class `FakeAccount` has no attribute `id` [missing-attribute]
--> tests/unit_tests/services/test_dataset_service_document.py:93:9
ERROR Object of class `FakeAccount` has no attribute `current_tenant_id` [missing-attribute]
|
Contributor
Pyrefly Type Coverage
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #38522
Related: #38518
Summary
DatasetService.delete_datasetfiresdataset_was_deletedand removes the dataset row with no check for in-flight indexing. Deleting a dataset mid-ingest races the running indexing pipeline againstclean_dataset_task: the pipeline keeps writing segments/chunks/vectors for rows the cleanup just removed, and its long-lived transactions can block the cleanup itself. #38518 reports the fallout at production scale — ~2.4M orphaneddocument_segments, ~830kchild_chunks, and ~34 GB of orphaned pgvector tables.Fix
delete_datasetnow checks for actively indexing documents before doing anything, and raises a newDatasetIndexingInProgressErrorwhen found. Both delete endpoints (console and service API) map it to a 409 with a clear message, exactly like the existingDatasetInUseErrorhandling on the same endpoints:The guard matches a document when:
indexing_status∈DocumentService._INDEXING_STATUSES(parsing/cleaning/splitting/indexing— the same set the document list uses for its "indexing" display status), andis_paused IS NOT trueBoth conditions are deliberate:
waiting(queued) documents don't block deletion. A queued task no-ops once the dataset rows are gone (_document_indexingloads the dataset first and returns if missing), so queued documents can't produce orphaned writes. Blocking on them would also strand console users — the UI has no pause control for queued documents (the pause button appears only for the four in-flight statuses).#38522 sketches two options: pause-and-await, or reject with a clear error. This implements the reject option. Pause-and-await inside a synchronous HTTP handler means unbounded blocking of a web worker, and
is_pausedcheckpoints are honored by the legacy indexing runner but not by the RAG-pipeline ingestion path that produced #38518 — so awaiting wouldn't reliably close the race anyway. Rejecting closes it at the entry point regardless of ingestion path.The check-then-delete window (a document starting to index between the check and the commit) remains, as acknowledged in the issue; closing it fully needs dataset-level locking across all status-mutating paths and is out of scope here. #38519 (cleanup robustness) complements this guard for anything that slips through.
Changes
services/dataset_service.py—_has_documents_indexinghelper + guard indelete_datasetservices/errors/dataset.py—DatasetIndexingInProgressErrorcontrollers/console/datasets/{error,datasets}.py,controllers/service_api/dataset/{error,dataset}.py— 409 mapping on both delete endpoints, service-API OpenAPI docs updated with the new 409 causemessagebodies on this endpoint (same pathdataset_in_useuses today)Testing
is_paused IS NOT true, EXISTS ondocuments.dataset_id)test_delete_dataset_in_use)tests/unit_tests/services/test_dataset_service_dataset.py: 83 passed ·tests/unit_tests/controllers/console/datasets/test_datasets.py: 71 passedruff check/ruff format: clean ·pyrefly checkon all changed source files: 0 errors