feat(server): impl doc gc (#15282)
#### PR Dependency Tree * **PR #15282** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added automated document cleanup to reconcile missing workspace docs, delete related stored data, and recover if the doc returns. * Added effect-based follow-up reconciliation for search indexing, Copilot embeddings, and comment attachment cleanup with explicit acknowledgements. * **Bug Fixes** * Deleted-document references now persist as dangling references rather than disappearing. * Improved document deletion flow to enforce permissions and ensure authorized deletions succeed. * **Tests** * Expanded coverage for cleanup recovery, indexing/embedding reconciliation, permissions, and reference semantics. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -126,37 +126,4 @@ impl BackendRuntime {
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn delete_doc_storage(&self, workspace_id: String, doc_id: String) -> napi::Result<()> {
|
||||
let pool = self.pool().await?;
|
||||
let mut tx = pool
|
||||
.begin()
|
||||
.await
|
||||
.map_err(|err| RuntimeError::database("DocStorage delete begin transaction failed", err))?;
|
||||
|
||||
sqlx::query("DELETE FROM snapshots WHERE workspace_id = $1 AND guid = $2")
|
||||
.bind(&workspace_id)
|
||||
.bind(&doc_id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|err| RuntimeError::database("DocStorage delete snapshot failed", err))?;
|
||||
sqlx::query("DELETE FROM updates WHERE workspace_id = $1 AND guid = $2")
|
||||
.bind(&workspace_id)
|
||||
.bind(&doc_id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|err| RuntimeError::database("DocStorage delete updates failed", err))?;
|
||||
sqlx::query("DELETE FROM snapshot_histories WHERE workspace_id = $1 AND guid = $2")
|
||||
.bind(&workspace_id)
|
||||
.bind(&doc_id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|err| RuntimeError::database("DocStorage delete histories failed", err))?;
|
||||
|
||||
tx.commit()
|
||||
.await
|
||||
.map_err(|err| RuntimeError::database("DocStorage delete commit failed", err))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,9 @@ fn migrations_include_runtime_tables_without_worker_heartbeats() {
|
||||
assert!(RUNTIME_MIGRATIONS.contains("runtime_states"));
|
||||
assert!(RUNTIME_MIGRATIONS.contains("runtime_gates"));
|
||||
assert!(RUNTIME_MIGRATIONS.contains("runtime_leases"));
|
||||
assert!(RUNTIME_MIGRATIONS.contains("blob_reconciliation_runs"));
|
||||
assert!(RUNTIME_MIGRATIONS.contains("blob_reconciliation_checkpoints"));
|
||||
assert!(RUNTIME_MIGRATIONS.contains("storage_reconciliation_runs"));
|
||||
assert!(RUNTIME_MIGRATIONS.contains("storage_reconciliation_checkpoints"));
|
||||
assert!(RUNTIME_MIGRATIONS.contains("document_cleanup_candidates"));
|
||||
assert!(RUNTIME_MIGRATIONS.contains("doc_blob_refs"));
|
||||
assert!(RUNTIME_MIGRATIONS.contains("blob_cleanup_candidates"));
|
||||
assert!(!RUNTIME_MIGRATIONS.contains("runtime_worker_heartbeats"));
|
||||
@@ -136,12 +137,10 @@ async fn insert_invite_quota_fixture(
|
||||
.bind(email)
|
||||
.execute(&pool)
|
||||
.await?;
|
||||
sqlx::query(
|
||||
"INSERT INTO workspaces (id, public, created_at) VALUES ($1, false, clock_timestamp() - interval '60 days')",
|
||||
)
|
||||
.bind(&workspace_id)
|
||||
.execute(&pool)
|
||||
.await?;
|
||||
sqlx::query("INSERT INTO workspaces (id, created_at) VALUES ($1, clock_timestamp() - interval '60 days')")
|
||||
.bind(&workspace_id)
|
||||
.execute(&pool)
|
||||
.await?;
|
||||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO effective_workspace_quota_states (
|
||||
|
||||
Reference in New Issue
Block a user