当前位置: 首页 > 知识库问答 >
问题:

并发启动函数并提前返回

彭洲
2023-03-14

我需要从我的FastAPI路径操作返回一个响应,但在此之前,我想发送一个缓慢的请求,我不需要等待该请求的结果,如果有任何错误,只需记录错误。我可以通过Python和FastAPI做到这一点吗?我不想将芹菜添加到项目中。

这是我目前掌握的情况,但它是同步运行的:

import asyncio
import requests


async def slow_request(data):
    url = 'https://external.service'
    response = requests.post(
        url=url,
        json=data,
        headers={'Auth-Header': settings.API_TOKEN}
    )
    if not response.status_code == 200:
        logger.error('response:', response.status_code)
        logger.error('data', data)


@router.post('/order/')
async def handle_order(order: Order):
    json_data = {
        'order': order
    }
    
    task = asyncio.create_task(
        slow_request(json_data)
    )
    await task

    return {'body': {'message': 'success'}}

共有2个答案

松昱
2023-03-14

问题其实是由两部分组成的

  • 请求库是同步的,因此requests.post(…)将阻塞事件循环,直到完成
  • 您不需要Web请求的结果来响应客户端,但您当前的处理程序在请求完成之前无法响应客户端(即使是异步的)

考虑将请求逻辑分离到另一个进程中,这样它就可以以自己的速度发生。

关键是您可以将工作放入某种队列中以最终完成,而无需直接需要结果来响应客户端。

您可以使用异步超文本传输协议请求库和一些回调集合,多重处理来生成一个新进程,或者更奇特的东西,比如独立程序(可能有管道或套接字来通信)。

也许这种形式对你有用

import base64
import json
import multiprocessing

URL_EXTERNAL_SERVICE = "https://example.com"
TIMEOUT_REQUESTS = (2, 10)  # always set a timeout for requests
SHARED_QUEUE = multiprocessing.Queue()  # may leak as unbounded

async def slow_request(data):
    SHARED_QUEUE.put(data)
    # now returns on successful queue put, rather than request completion

def requesting_loop(logger, Q, url, token):
    while True:  # expects to be a daemon
        data = json.dumps(Q.get())  # block until retrieval (non-daemon can use sentinel here)
        response = requests.post(
            url,
            json=data,
            headers={'Auth-Header': token},
            timeout=TIMEOUT_REQUESTS,
        )
        # raise_for_status() --> try/except --> log + continue
        if response.status_code != 200:
            logger.error('call to {} failed (code={}) with data: {}'.format(
                url, response.status_code,
                "base64:" + base64.b64encode(data.encode())
            ))

def startup():  # run me when starting
    # do whatever is needed for logger
    # create a pool instead if you may need to process a lot of requests
    p = multiprocessing.Process(
        target=requesting_loop,
        kwargs={"logger": logger, "Q": SHARED_QUEUE, "url": URL_EXTERNAL_SERVICE, "token": settings.API_TOKEN},
        daemon=True
    )
    p.start()
赏光霁
2023-03-14

好的,如果没有人想在这里发布答案,那么解决方案如下:

我们可以按照alex_noname的建议删除等待任务行。它将起作用create_task因为计划任务,我们不再等待它的完成。

@router.post('/order/')
async def handle_order(order: Order):
    json_data = {
        'order': order
    }
    
    task = asyncio.create_task(
        slow_request(json_data)
    )

    return {'body': {'message': 'success'}}

正如HTF所建议的那样,我最终使用了背景任务,因为我已经在使用FastAPI了,而且这个解决方案对我来说似乎更简洁。

@router.post('/order/')
async def handle_order(order: Order, background_tasks: BackgroundTasks):
    json_data = {
        'order': order
    }
    
    background_tasks.add_task(slow_request, json_data)

    return {'body': {'message': 'success'}}

这甚至在< code > def slow _ request(data):之前没有< code>async的情况下也能工作

 类似资料:
  • 本文向大家介绍ASP 信息提示函数并作返回或者转向,包括了ASP 信息提示函数并作返回或者转向的使用技巧和注意事项,需要的朋友参考一下 有时候我们在写asp的时候需要给用户一些反馈信息,这个自定义的返回信息函数,很方便大家使用 具体的使用方法就不说了,很简单

  • 以下是我的小程序的要点 一个python脚本,用于检查某个目录中是否有新文件(电影文件),并相应地更新sqlite3数据库,从而将要处理的文件排队。使用launchctl每分钟运行一次。 另一个python脚本,使用HandBrake命令行界面进行文件转换的实际处理。还可以使用launchctl每分钟运行一次。 在第二个脚本中,转换完成后,我想启动一个applescript,将文件导入到iTune

  • 问题内容: 我正在编写Go程序。从这个Go程序中,我想调用另一个文件中定义的Python函数并接收该函数的返回值,以便可以在Go程序的后续处理中使用它。我在将所有返回的数据恢复到我的Go程序时遇到了麻烦。以下是我认为可行的最低示例,但显然无效: gofile.go pythonfile.py 如果我打电话,我得到以下输出: 一些注意事项: 我在Python调用中使用该标志,因此可以直接调用该函数。

  • 请注意,当您使用 Jetty NPN 库需要提供它的位置通过 bootclasspath 的 JVM 参数。这一步是必需的,这样才能访问 SslEngine接口。(-Xbootclasspath 选项允许您覆盖标准 JDK 附带的实现类)。 下面的清单显示了特殊的参数(-Xbootclasspath)使用。 Listing 12.7 SpdyServer implementation java -

  • This page will help you install OCaml, the Dune build system, and support for your favourite text editor or IDE. These instructions work on Windows, Unix systems like Linux, and macOS. Installing OCam

  • 本文向大家介绍Swift函数提前返回实例详解,包括了Swift函数提前返回实例详解的使用技巧和注意事项,需要的朋友参考一下 简评: 函数是一个组织在一起语句集合,以执行特定任务。Swift 函数类似于简单 C 函数以及复杂的 Objective C 语言函数。 它使我们能够通过函数调用内部的局部和全局参数值。 像其他任何语言一样 swift 函数也遵循相同的步骤。 函数声明:它告诉编译器有关的函数