Implement ownership model for all cached content deletion
- cache_service.delete_content: Remove user's ownership link first, only delete actual file if no other owners remain - cache_manager.discard_activity_outputs_only: Check if outputs and intermediates are used by other activities before deleting - run_service.discard_run: Now cleans up run outputs/intermediates (only if not shared by other runs) - home.py clear_user_data: Use ownership model for effects and media deletion instead of directly deleting files The ownership model ensures: 1. Multiple users can "own" the same cached content 2. Deleting removes the user's ownership link (item_types entry) 3. Actual files only deleted when no owners remain (garbage collection) 4. Shared intermediates between runs are preserved Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -467,10 +467,13 @@ class RunService:
|
||||
username: str,
|
||||
) -> Tuple[bool, Optional[str]]:
|
||||
"""
|
||||
Discard (delete) a run record.
|
||||
Discard (delete) a run record and clean up outputs/intermediates.
|
||||
|
||||
Note: This removes the run record but not the output content.
|
||||
Outputs and intermediates are only deleted if not used by other runs.
|
||||
"""
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
run = await self.get_run(run_id)
|
||||
if not run:
|
||||
return False, f"Run {run_id} not found"
|
||||
@@ -480,6 +483,18 @@ class RunService:
|
||||
if run_owner and run_owner not in (username, actor_id):
|
||||
return False, "Access denied"
|
||||
|
||||
# Clean up activity outputs/intermediates (only if orphaned)
|
||||
# The activity_id is the same as run_id
|
||||
try:
|
||||
success, msg = self.cache.discard_activity_outputs_only(run_id)
|
||||
if success:
|
||||
logger.info(f"Cleaned up run {run_id}: {msg}")
|
||||
else:
|
||||
# Activity might not exist (old runs), that's OK
|
||||
logger.debug(f"No activity cleanup for {run_id}: {msg}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to cleanup activity for {run_id}: {e}")
|
||||
|
||||
# Remove task_id mapping from Redis
|
||||
self.redis.delete(f"{self.task_key_prefix}{run_id}")
|
||||
|
||||
@@ -487,8 +502,7 @@ class RunService:
|
||||
try:
|
||||
await self.db.delete_run_cache(run_id)
|
||||
except Exception as e:
|
||||
import logging
|
||||
logging.getLogger(__name__).warning(f"Failed to delete run_cache for {run_id}: {e}")
|
||||
logger.warning(f"Failed to delete run_cache for {run_id}: {e}")
|
||||
|
||||
# Remove pending run if exists
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user