You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flask路由中使用asyncio上传S3时无需await直接返回JSON

解决方案

方法1:使用threading开启后台线程(最轻量,无需额外依赖)

该方案改造成本极低,适合小规模、允许偶尔丢失任务的场景。首先修正你现有代码的两个问题:

  1. 普通同步Flask路由不能直接使用await关键字,会直接抛出语法错误
  2. 你给同步的boto3上传逻辑加async装饰器没有实际作用,内部还是阻塞执行

修改后的可用代码如下:

import threading
import os
import logging
from flask import request, jsonify
from werkzeug.utils import secure_filename
import boto3
from botocore.exceptions import ClientError

# s3客户端建议全局初始化,不要每次请求重复创建
s3_client = boto3.client('s3')
logger = logging.getLogger(__name__)
UPLOAD_FOLDER = "你的本地存储目录路径"

def upload_file(file_name, bucket, object_name=None):
    try:
        object_name = object_name if object_name else file_name
        file_path = os.path.join(UPLOAD_FOLDER, file_name)
        response = s3_client.upload_file(file_path, bucket, object_name)
        logger.info(f"S3上传完成: {response}")
        # 上传完成后删除本地文件,避免磁盘占用
        os.remove(file_path)
    except ClientError as e:
        logger.error(f"S3上传失败: {e}")
        return False
    return True

@jobs.route("/", methods=["POST"])
def process_video():
    file = request.files['file']
    logger.info("收到上传文件: %s" % (file.filename,))
    filename = secure_filename(file.filename)
    file_path = os.path.join(UPLOAD_FOLDER, filename)
    file.save(file_path)
    # 开启守护线程执行上传逻辑,不需要等待执行完成
    upload_thread = threading.Thread(
        target=upload_file,
        args=(filename, 's3-bucket'),
        daemon=True # 设为守护线程,主进程退出时自动销毁线程
    )
    upload_thread.start()
    # 直接返回响应,无需等待上传结束
    return jsonify({"hello": "world demo"})

注意事项:

  • 守护线程会在Flask进程退出时直接终止,如果上传过程中服务重启,正在执行的任务会丢失
  • 高并发场景下大量上传请求会创建过多线程,可能导致服务性能下降,这种情况建议用线程池限制最大并发数

方法2:使用任务队列(适合生产环境、重要任务场景)

如果上传任务不能丢失、并发量较高,建议使用成熟的任务队列框架Celery,搭配Redis/RabbitMQ做中间件,任务会持久化存储,即使服务重启也不会丢失未执行的任务。
核心逻辑是把上传函数注册为Celery任务,路由里只需要提交任务到队列就直接返回,由独立的Worker进程执行上传逻辑,核心示例代码:

# 初始化Celery
from celery import Celery
celery = Celery('tasks', broker='redis://localhost:6379/0')

@celery.task
def upload_file(file_name, bucket, object_name=None):
    # 上传逻辑和方法1完全一致
    pass

@jobs.route("/", methods=["POST"])
def process_video():
    # 保存本地文件的逻辑和方法1一致
    upload_file.delay(filename, 's3-bucket') # 提交异步任务
    return jsonify({"hello": "world demo"})

内容的提问来源于stack exchange,提问作者DevZer0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 02:54:05