fix(dataset): clean deleted dataset in committed batches to avoid orphaned data#38519
fix(dataset): clean deleted dataset in committed batches to avoid orphaned data#38519shaba wants to merge 2 commits into
Conversation
9d6aaee to
27b6d51
Compare
…haned data clean_dataset_task deleted all documents, segments and child chunks of a deleted dataset in a single transaction using large IN (...) statements. On a multi-million-row dataset this times out or gets blocked by concurrent indexing transactions; the exception then rolls back the whole task, so nothing is deleted and the documents, segments, child chunks and the pgvector index table are left orphaned forever (the dataset row itself is already gone). Delete each child table in bounded, individually committed batches so partial progress is durable and one failing step no longer orphans everything. Also explicitly drop child_chunks as a fallback when the vector-store cleanup did not remove them. Refs langgenius#38518
27b6d51 to
5a632c3
Compare
|
Scope / relationship to other work (see #38518): This PR fixes the cleanup-robustness half — It is complementary to #37773 (document-vs-dataset segment deletion race) — a different code path, no overlap/conflict. The remaining part called out in #38518 — adding a guard so a dataset can't be deleted while its documents are still indexing (cancel/await in-flight indexing in Existing unit tests ( |
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-07-07 16:19:36.924089772 +0000
+++ /tmp/pyrefly_pr.txt 2026-07-07 16:19:27.596999387 +0000
@@ -2111,9 +2111,9 @@
ERROR `SimpleNamespace` is not assignable to attribute `_current_tenant` with type `Tenant | None` [bad-assignment]
--> tests/unit_tests/controllers/console/test_workspace_members.py:186:43
ERROR Argument `Literal['app']` is not assignable to parameter `resource_type` with type `RBACResourceScope` in function `controllers.common.wraps._extract_resource_id` [bad-argument-type]
- --> tests/unit_tests/controllers/console/test_wraps.py:305:41
+ --> tests/unit_tests/controllers/console/test_wraps.py:298:41
ERROR Argument `Literal['app']` is not assignable to parameter `resource_type` with type `RBACResourceScope` in function `controllers.common.wraps._extract_resource_id` [bad-argument-type]
- --> tests/unit_tests/controllers/console/test_wraps.py:313:41
+ --> tests/unit_tests/controllers/console/test_wraps.py:306:41
ERROR `SimpleNamespace` is not assignable to attribute `db` with type `SQLAlchemy` [bad-assignment]
--> tests/unit_tests/controllers/files/test_image_preview.py:18:17
ERROR `SimpleNamespace` is not assignable to attribute `request` with type `Request` [bad-assignment]
@@ -7434,6 +7434,18 @@
--> tests/unit_tests/services/test_annotation_service.py:1194:59
ERROR TypedDict `AnnotationSettingDisabledDict` does not have key `embedding_model` [bad-typed-dict-key]
--> tests/unit_tests/services/test_annotation_service.py:1231:27
+ERROR Argument `SimpleNamespace` is not assignable to parameter `session` with type `Session` in function `services.app_dsl_service.AppDslService.__init__` [bad-argument-type]
+ --> tests/unit_tests/services/test_app_dsl_service.py:9:37
+ERROR Argument `SimpleNamespace` is not assignable to parameter `account` with type `Account` in function `services.app_dsl_service.AppDslService.import_app` [bad-argument-type]
+ --> tests/unit_tests/services/test_app_dsl_service.py:12:17
+ERROR Argument `SimpleNamespace` is not assignable to parameter `session` with type `Session` in function `services.app_dsl_service.AppDslService.__init__` [bad-argument-type]
+ --> tests/unit_tests/services/test_app_dsl_service.py:27:37
+ERROR Argument `SimpleNamespace` is not assignable to parameter `account` with type `Account` in function `services.app_dsl_service.AppDslService.import_app` [bad-argument-type]
+ --> tests/unit_tests/services/test_app_dsl_service.py:30:17
+ERROR Argument `SimpleNamespace` is not assignable to parameter `session` with type `Session` in function `services.app_dsl_service.AppDslService.__init__` [bad-argument-type]
+ --> tests/unit_tests/services/test_app_dsl_service.py:44:37
+ERROR Argument `SimpleNamespace` is not assignable to parameter `account` with type `Account` in function `services.app_dsl_service.AppDslService.import_app` [bad-argument-type]
+ --> tests/unit_tests/services/test_app_dsl_service.py:47:17
ERROR Class member `_TrackingRateLimit.exit` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
--> tests/unit_tests/services/test_app_generate_service.py:560:17
ERROR Class member `_TrackingRateLimit.exit` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]
@@ -7689,13 +7701,13 @@
ERROR Argument `None` is not assignable to parameter `plan` with type `CloudPlan` in function `RagPipelineTaskProxyTestDataFactory.create_mock_features` [bad-argument-type]
--> tests/unit_tests/services/test_rag_pipeline_task_proxy.py:442:109
ERROR Argument `dict[str, Any]` is not assignable to parameter `node_config` with type `NodeConfigDict` in function `services.trigger.schedule_service.ScheduleService.to_schedule_config` [bad-argument-type]
- --> tests/unit_tests/services/test_schedule_service.py:536:61
+ --> tests/unit_tests/services/test_schedule_service.py:521:61
ERROR Argument `dict[str, str | dict[str, str]]` is not assignable to parameter `node_config` with type `NodeConfigDict` in function `services.trigger.schedule_service.ScheduleService.to_schedule_config` [bad-argument-type]
- --> tests/unit_tests/services/test_schedule_service.py:550:56
+ --> tests/unit_tests/services/test_schedule_service.py:535:56
ERROR Argument `dict[str, str | dict[str, str | dict[str, str]]]` is not assignable to parameter `node_config` with type `NodeConfigDict` in function `services.trigger.schedule_service.ScheduleService.to_schedule_config` [bad-argument-type]
- --> tests/unit_tests/services/test_schedule_service.py:567:61
+ --> tests/unit_tests/services/test_schedule_service.py:552:61
ERROR Argument `dict[str, str | dict[str, str]]` is not assignable to parameter `node_config` with type `NodeConfigDict` in function `services.trigger.schedule_service.ScheduleService.to_schedule_config` [bad-argument-type]
- --> tests/unit_tests/services/test_schedule_service.py:579:56
+ --> tests/unit_tests/services/test_schedule_service.py:564:56
ERROR Argument `SimpleNamespace` is not assignable to parameter `session` with type `Session` in function `services.snippet_dsl_service.SnippetDslService.__init__` [bad-argument-type]
--> tests/unit_tests/services/test_snippet_dsl_service.py:33:41
ERROR Argument `SimpleNamespace` is not assignable to parameter `account` with type `Account` in function `services.snippet_dsl_service.SnippetDslService.import_snippet` [bad-argument-type]
|
Pyrefly Type Coverage
|
Summary
Fixes orphaned data left behind when a knowledge base is deleted (especially while its documents are still indexing). See #38518.
clean_dataset_taskdeleted all documents, segments and child chunks of a deleted dataset in a single transaction using largeIN (...)statements (after loading every segment/document into memory). On a large dataset this times out or gets blocked by the still-running indexing transactions; the exception then hitssession.rollback(), so nothing is deleted and thedocuments,document_segments,child_chunksrows and theembedding_vector_index_<uuid>_nodpgvector table are orphaned forever — thedatasetsrow itself is already gone, so the cleanup never gets retried.Real-world impact we hit: deleting 3 knowledge bases mid-indexing left ~2.4M orphaned
document_segments, ~830kchild_chunksand ~34 GB of pgvector tables that had to be removed by hand.What changed
api/tasks/clean_dataset_task.py:document_segments,documents,child_chunks) in bounded, individually committed batches (_DELETE_BATCH_SIZE = 1000), so partial progress is durable and a timeout/lock no longer rolls back the entire cleanup.try/exceptas before.child_chunksbydataset_idas a fallback for when the vector-storeclean(..., delete_child_chunks=True)did not remove them.UploadFilerows; attachments and the pipeline/workflow are still cleaned.How to test
document_segments/child_chunks/documentsand noembedding_vector_index_<id>_nodtable survives.test_dataset_service_delete_datasetservice tests mockclean_dataset_task.delay, so they are unaffected.Refs #38518