mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-09-17 15:27:15 +00:00
fix(maintenance): guard media cache cleanup and annotate exception suppression
- Safely resolve media_cache via getattr in cleanup_expired_files to prevent AttributeError when storage_mgr is unset in cloud/test fixtures - Only attach 'media_files' in cleanup return dictionary when media cache is active on singleton, preserving exact return contract for cloud maintenance tests - Add explanatory comments to exception suppression in MediaCache.touch and cleanup loops to address code-quality review findings
This commit is contained in:
@@ -91,25 +91,29 @@ class MaintenanceService:
|
|||||||
0,
|
0,
|
||||||
'storage.media_cache.max_size_mb',
|
'storage.media_cache.max_size_mb',
|
||||||
)
|
)
|
||||||
|
media_cache = getattr(getattr(self.ap, 'storage_mgr', None), 'media_cache', None)
|
||||||
|
is_singleton = await self._is_oss_singleton(context)
|
||||||
media_cleanup = (
|
media_cleanup = (
|
||||||
await self.ap.storage_mgr.media_cache.cleanup(
|
await media_cache.cleanup(
|
||||||
media_retention_days,
|
media_retention_days,
|
||||||
media_max_size_mb,
|
media_max_size_mb,
|
||||||
)
|
)
|
||||||
if hasattr(self.ap.storage_mgr, 'media_cache') and await self._is_oss_singleton(context)
|
if media_cache is not None and is_singleton
|
||||||
else {}
|
else {}
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
result = {
|
||||||
'uploaded_files': await self._cleanup_expired_uploaded_files(context, upload_retention_days),
|
'uploaded_files': await self._cleanup_expired_uploaded_files(context, upload_retention_days),
|
||||||
'log_files': await asyncio.to_thread(
|
'log_files': await asyncio.to_thread(
|
||||||
self._cleanup_expired_log_files,
|
self._cleanup_expired_log_files,
|
||||||
log_retention_days,
|
log_retention_days,
|
||||||
)
|
)
|
||||||
if await self._is_oss_singleton(context)
|
if is_singleton
|
||||||
else 0,
|
else 0,
|
||||||
'media_files': media_cleanup.get('expired_deleted', 0) + media_cleanup.get('size_deleted', 0),
|
|
||||||
}
|
}
|
||||||
|
if media_cache is not None and is_singleton:
|
||||||
|
result['media_files'] = media_cleanup.get('expired_deleted', 0) + media_cleanup.get('size_deleted', 0)
|
||||||
|
return result
|
||||||
|
|
||||||
async def get_storage_analysis(self, context: TenantContext) -> dict[str, Any]:
|
async def get_storage_analysis(self, context: TenantContext) -> dict[str, Any]:
|
||||||
require_workspace_uuid(context)
|
require_workspace_uuid(context)
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ class MediaCache:
|
|||||||
try:
|
try:
|
||||||
await asyncio.to_thread(os.utime, full_path, (now, now))
|
await asyncio.to_thread(os.utime, full_path, (now, now))
|
||||||
except Exception:
|
except Exception:
|
||||||
|
# Failures to update mtime are intentionally ignored because LRU touch is opportunistic.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def cleanup(
|
async def cleanup(
|
||||||
@@ -166,6 +167,7 @@ class MediaCache:
|
|||||||
expired_deleted += 1
|
expired_deleted += 1
|
||||||
bytes_freed += stat.st_size
|
bytes_freed += stat.st_size
|
||||||
except OSError:
|
except OSError:
|
||||||
|
# Best-effort cleanup; file may already be gone or temporarily inaccessible.
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
remaining.append((entry, stat.st_size, stat.st_mtime))
|
remaining.append((entry, stat.st_size, stat.st_mtime))
|
||||||
@@ -184,7 +186,8 @@ class MediaCache:
|
|||||||
bytes_freed += size
|
bytes_freed += size
|
||||||
total_bytes -= size
|
total_bytes -= size
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
# Best-effort cleanup; file may already be gone or temporarily inaccessible.
|
||||||
|
continue
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'expired_deleted': expired_deleted,
|
'expired_deleted': expired_deleted,
|
||||||
|
|||||||
Reference in New Issue
Block a user