关于fastapi异步接口卡死的坑及解决

 更新时间:2024年06月29日 08:38:24   作者:brandon_l  
这篇文章主要介绍了关于fastapi异步接口卡死的坑及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

背景

开发任务是使用fastapi去写一个对工业设备(PLC)的通信接口,方便其他后端服务与设备对接,将设备的功能抽象出来供MES调用。

通信协议是使用modbus TCP,由于fastapi是异步框架,很多以前在同步函数里开发的代码移植过来发现出现了异常,这也是不断踩坑的过程,问题解决之后也能体会到异步框架的优美与高效。

问题细节

在视图函数中我们需要创建一个socket连接,使用它跟plc进行通信,完毕之后还要记得关闭该连接,否则就会造成异步框架的卡死,其他请求就进不来了。

刚开始我的代码是这样的:

@router.put("/start/{id}")
async def start(
    id:int,
    batsize:int=Body(default=15,description='批次大小'),
    noksize:int=Body(default=3,description='最大连续失败次数')
    ):

    dip = await PLC.get(pk=id)   # 配置数据库中查询设备网络信息
    zmqconn = get_conn(dip.host,dip.port)   # 获取网络连接
    # 发送命令
    try:
        ret = zmqconn.request(action='start_batch',rqargs={'batch_size':batsize,'nok_num':noksize})
    except Exception as e:
        raise HTTPException(status_code=503,detail=str(e))
    else:
        return ret

​​​​写完之后我自己测试了一下,发现是可以正常发起命令的,而且接口也返回了期望的结果,但是我快速点了几下,发现问题就来了,第六下的时候,接口卡住无法返回,异步函数中也不执行任何动作,这在之前的同步代码中是没有出现的。

后来我经过调试发现是socket连接并没有成功创建,怀疑是之前的连接没有关闭,导致了网络阻塞,于是加入了关闭连接的代码。

@router.put("/start/{id}")
async def start(
    id:int,
    batsize:int=Body(default=15,description='批次大小'),
    noksize:int=Body(default=3,description='最大连续失败次数')
    ):

    dip = await PLC.get(pk=id)
    zmqconn = get_conn(dip.host,dip.port)
        
    try:
        ret = zmqconn.request(action='start_batch',rqargs={'batch_size':batsize,'nok_num':noksize})
    except Exception as e:
        raise HTTPException(status_code=503,detail=str(e))
    finally:
        zmqconn.close()
    return ret

这个时候就完全没有卡住的问题了,接口可以一直点。

所以对于异步函数,我们一定要注意手动释放资源,否则可能会造成意想不到的问题。

fastapi依赖注入

但是这又出现一个问题,我们的服务是经常用到前面的socket框架的,其他接口也要用到,总不能每个接口都把这段代码复制粘贴一边吧。

fastapi作为最优秀的异步框架,有一个很大的特点就是非常苛刻的代码复用性,它在设计的时候考虑到了重复代码的问题。

至于苛刻到什么程度呢,举个例子,如果不同的接口用了相同的一组参数,那么你可以把这组参数进行封装,写到依赖里面,用的时候引入一下,那么你新的接口就有了一组一模一样的参数。

这里我们利用fastapi的依赖注入,把接口参数以及socket连接都封装起来,供其他接口调用。

依赖代码

async def get_conn_dep(
    id:int = Path(description='路径参数,设备id'),
):
    dip = await PLC.get(pk=id)
    try:
        zmqconn = get_conn(dip.host,dip.port)
        yield zmqconn                # 向接口函数注入链接
    finally:
        zmqconn.close()     # 接口函数执行完毕后会异步执行关闭

而我们的接口函数就可以非常精简

@router.put("/start/{id}")
async def start(
    zmqconn = Depends(get_conn_dep),     # 这一行直接复用了一堆代码以及相应的路径字段,简直太优雅了
    batsize:int=Body(default=15,description='批次大小'),
    noksize:int=Body(default=3,description='最大连续失败次数')
    ):

    try:
        ret = zmqconn.request(action='start_batch',rqargs={'batch_size':batsize,'nok_num':noksize})
    except Exception as e:
        raise HTTPException(status_code=503,detail=str(e))
    else:
        return ret

我们使用swagger疯狂点击该接口,并传入不同的参数进行测试,发现接口响应非常流畅,异常处理的时候也返回了我们想要的错误信息。

我们上面的代码使用了fastapi异步接口(据说性能逼近go),并使用了tortoise异步ORM,tortoise的使用与django-orm几乎一样,但它是一个纯异步orm,这两个配合起来开发简直是非常的舒服。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • pandas or sql计算前后两行数据间的增值方法

    pandas or sql计算前后两行数据间的增值方法

    下面小编就为大家分享一篇pandas or sql计算前后两行数据间的增值方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04
  • Python导入模块的3种方式小结

    Python导入模块的3种方式小结

    本文主要介绍了Python导入模块的3种方式小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • Python生成requirements.txt的三种方法

    Python生成requirements.txt的三种方法

    requirements.txt 文件通常用于列出项目所需的所有Python包及其版本,本文主要介绍了Python生成requirements.txt的三种方法,具有一定的参考价值,感兴趣的可以了解一下
    2024-07-07
  • unittest+coverage单元测试代码覆盖操作实例详解

    unittest+coverage单元测试代码覆盖操作实例详解

    这篇文章主要为大家详细介绍了unittest+coverage单元测试代码覆盖操作的实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • 一文详解Python的pyc文件

    一文详解Python的pyc文件

    Python 程序在执行过程中,会产生一些中间文件,其中最常见的就是 pyc 文件,pyc 文件是 Python 的二进制字节码文件,本文将通过简洁的语言、实际的代码和案例,通俗易懂地解释 pyc 文件的相关知识,感兴趣的小伙伴跟着小编一起来看看吧
    2024-12-12
  • 使用Python的package机制如何简化utils包设计详解

    使用Python的package机制如何简化utils包设计详解

    这篇文章主要给大家介绍了关于使用Python的package机制如何简化utils包设计的相关资料,文中通过示例代码的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-12-12
  • Django中外键使用总结

    Django中外键使用总结

    本文主要介绍了Django中外键使用总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • Python竟能画这么漂亮的花,帅呆了(代码分享)

    Python竟能画这么漂亮的花,帅呆了(代码分享)

    这篇文章主要介绍了用Python作图的一个简单实例,通过turtle模块实现作图,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Python实现爬取网页中动态加载的数据

    Python实现爬取网页中动态加载的数据

    这篇文章主要介绍了Python实现爬取网页中动态加载的数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • 一篇文章学会两种将python打包成exe的方式

    一篇文章学会两种将python打包成exe的方式

    最近有部分小伙伴问我,python 写的项目可不可以打包成exe程序,放到没有python环境上的电脑中执行? 答案当然是可以的,下面这篇文章主要给大家介绍了如何通过一篇文章学会两种将pyton打包成exe的方式,需要的朋友可以参考下
    2021-11-11

最新评论