【问题标题】:Respond to an Upload confimation and then process file in Sanic响应上传确认,然后在 Sanic 中处理文件
【发布时间】:2020-11-28 22:21:14
【问题描述】:

我正在尝试处理用户上传的文件。但是,我希望用户在上传完成后得到响应并终止连接但继续处理文件。我的代码如下所示:

@app.route("/upload", methods=['POST'])
async def upload(request):
        try:
            file = request.files.get("file")
        except Exception as e:
            return json({"Received": False})

    await process(file)
    return response.text("File has been uploaded successfully")


async def process(file):
    """ Processing File and generate data"""
    ...
    result = await foo(data)
    

在当前框架中,用户必须等待该过程完成。我希望用户得到回复说:

“文件已上传成功”

并终止连接,但仍继续处理(文件)。

【问题讨论】:

    标签: python api asynchronous sanic


    【解决方案1】:

    我认为您在这里有两种可能的解决方案。第一个会稍微偏离您的要求,因为它不会终止连接。但是,我认为这是一个可行的解决方案,所以我也提供了它。如果不是为了您的利益,也许是为了其他有类似需求的人。

    选项 #1 - 流式响应

    此选项是一种流式响应,您可以在其中立即发回第一部分,然后根据需要继续处理响应。现在,这显然在某种程度上取决于我们正在谈论的多少处理。如果它会有点长(选择任意时间,60 秒),那么这个解决方案可能不起作用。

    import asyncio
    from functools import partial
    
    from sanic import Sanic
    from sanic.response import json, stream
    
    app = Sanic(__name__)
    
    
    async def process(file, response):
        print(file, flush=True)
        await response.protocol.push_data(b"0x0")
        await response.write("File has been uploaded successfully\n")
        await asyncio.sleep(2)
        await response.write("33% processed\n")
        await asyncio.sleep(2)
        await response.write("66% processed\n")
        await asyncio.sleep(2)
        await response.write("100% processed\n")
    
    
    @app.post("/")
    async def upload(request):
        try:
            file = request.files.get("file")
        except Exception:
            return json({"Received": False})
    
        return stream(partial(process, file), chunked=False)
    
    

    选项 #2 - 后台任务

    我相信这正是您想要的。立即响应(关闭连接)。我们使用processing 并使用add_task 将其推到后台。

    import asyncio
    from functools import partial
    
    from sanic import Sanic
    from sanic.response import json, text
    
    app = Sanic(__name__)
    
    
    async def process(file,):
        await asyncio.sleep(3)
        print(f"{file=}", flush=True)
    
    
    @app.post("/")
    async def upload(request):
        try:
            file = request.files.get("file")
        except Exception:
            return json({"Received": False})
    
        request.app.add_task(process(file))
    
        return text("File has been uploaded successfully")
    

    作为另一种选择,我将here is an example 放在一起,处理程序将任务推送到队列,并且有一个单独的“工作人员”正在排空队列并执行任务。

    【讨论】:

    • 非常感谢!!选项 #2 正是我想要的!
    猜你喜欢
    • 1970-01-01
    • 2017-10-07
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-21
    • 1970-01-01
    相关资源
    最近更新 更多