You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

5.1 KiB

文件夹服务阿里云 OSS 集成

日期:2026-02-04
类型:功能完善
影响范围:后端 - 文件夹服务(Celery 任务)


变更概述

将文件夹导出和清理任务中的对象存储集成从 TODO 状态更新为使用现有的阿里云 OSS 实现。


变更内容

1. 导出任务 OSS 上传

文件server/app/tasks/folder_export_tasks.py

变更前

async def _upload_to_storage(zip_path: Path, folder_id: UUID) -> str:
    # TODO: 实际实现 MinIO 上传
    # 模拟上传
    time.sleep(1)
    file_url = f"https://cdn.example.com/exports/folders/{folder_id}.zip"
    return file_url

变更后

async def _upload_to_storage(zip_path: Path, folder_id: UUID) -> str:
    """上传到对象存储(阿里云 OSS)"""
    from app.core.storage import StorageService
    
    # 读取 ZIP 文件内容
    with open(zip_path, 'rb') as f:
        file_content = f.read()
    
    # 使用 StorageService 上传到 OSS
    storage = StorageService()
    object_name = f"exports/folders/{folder_id}.zip"
    file_url = await storage.upload_bytes(
        data=file_content,
        object_name=object_name,
        content_type='application/zip'
    )
    
    logger.info("文件上传完成: %s", file_url)
    return file_url

说明

  • 使用现有的 StorageService.upload_bytes() 方法
  • 基于 boto3 S3 兼容协议,支持阿里云 OSS
  • 自动处理文件 URL 生成

2. 清理任务 OSS 删除

文件server/app/tasks/folder_cleanup_tasks.py

变更前

async def _delete_storage_file(file_url: str) -> None:
    # TODO: 实际实现 MinIO 删除
    logger.info("删除存储文件: %s", file_url)

变更后

async def _delete_storage_file(file_url: str) -> None:
    """删除对象存储中的文件(阿里云 OSS)"""
    from app.core.storage import StorageService
    from app.core.config import settings
    
    # 从 URL 中提取 object_name
    if settings.S3_PUBLIC_URL and file_url.startswith(settings.S3_PUBLIC_URL):
        object_name = file_url.replace(f"{settings.S3_PUBLIC_URL}/", "")
    else:
        # 兼容其他 URL 格式
        parts = file_url.split('/')
        object_name = '/'.join(parts[-3:])
    
    # 使用 StorageService 删除文件
    storage = StorageService()
    await storage.delete_file(object_name)
    
    logger.info("删除存储文件: %s (object_name: %s)", file_url, object_name)

说明

  • 使用现有的 StorageService.delete_file() 方法
  • 从 URL 中提取 object_name
  • 支持多种 URL 格式

技术实现

StorageService 架构

位置server/app/core/storage.py

核心功能

class StorageService:
    """对象存储服务 - 基于 boto3 S3 兼容协议"""
    
    async def upload_bytes(
        self,
        data: bytes,
        object_name: str,
        content_type: Optional[str] = None
    ) -> str:
        """上传字节数据到对象存储"""
        # 使用 boto3 S3 客户端上传
        # 返回公开访问 URL
    
    async def delete_file(self, object_name: str) -> None:
        """删除文件"""
        # 使用 boto3 S3 客户端删除

配置

  • S3_ENDPOINT_URL - 阿里云 OSS Endpoint
  • S3_ACCESS_KEY_ID - AccessKey ID
  • S3_SECRET_ACCESS_KEY - AccessKey Secret
  • S3_BUCKET_NAME - Bucket 名称
  • S3_REGION - 区域
  • S3_PUBLIC_URL - 公开访问 URL 前缀

参考实现

项目中已有多处使用 StorageService 的实现:

  1. AI 任务文件上传server/app/tasks/ai_tasks.py

    • _download_and_upload_file() - 下载并上传文件
    • _upload_file_from_bytes() - 从字节数据上传
  2. 文件存储服务server/app/services/file_storage_service.py

    • upload_file() - 带去重的文件上传
    • cleanup_unused_files() - 清理无引用文件

测试验证

1. 上传测试

# 测试导出任务上传
from app.tasks.folder_export_tasks import process_folder_export

# 创建导出任务
job_id = "..."
result = process_folder_export.apply_async(args=[job_id])

# 验证文件 URL
assert result.get()['file_url'].startswith(settings.S3_PUBLIC_URL)

2. 删除测试

# 测试清理任务删除
from app.tasks.folder_cleanup_tasks import cleanup_expired_exports

# 运行清理任务
result = cleanup_expired_exports.apply()

# 验证删除结果
assert result.get()['deleted_count'] > 0

相关文档


总结

本次变更完成了文件夹服务与阿里云 OSS 的集成:

  1. 导出任务上传 - 使用 StorageService.upload_bytes()
  2. 清理任务删除 - 使用 StorageService.delete_file()
  3. 配置复用 - 使用现有的 S3 兼容配置
  4. 代码一致性 - 与项目其他模块保持一致

文件夹服务现已完全集成阿里云 OSS,可以正常处理文件导出和清理任务。