在 Python FastAPI 应用程序中启动异步后台守护进程

Арс*_*чко 14 python async-await python-asyncio fastapi

我正在使用 FastAPI 为分析系统构建异步后端。问题是它必须: a) 侦听 API 调用并始终可用;b) 定期执行数据收集任务(解析数据并将其保存到数据库中)。

我编写了这个函数来充当守护进程:

    async def start_metering_daemon(self) -> None:
        """sets a never ending task for metering"""
        while True:
            delay: int = self._get_delay()  # delay in seconds until next execution
            await asyncio.sleep(delay)
            await self.gather_meterings()  # perfom data gathering
Run Code Online (Sandbox Code Playgroud)

我想要实现的是,当应用程序启动时,它还会将此守护程序函数添加到主事件循环中,并在有时间时执行它。然而,我一直无法找到适合任务规模的合适解决方案(添加芹菜和类似的东西是一种矫枉过正)。

我尝试过以下方法来实现这一目标,但没有一个有效:

@app.on_event("startup")
async def startup_event() -> None:
    """tasks to do at server startup"""
    await Gatherer().start_metering_daemon()
Run Code Online (Sandbox Code Playgroud)

结果:由于线程被阻塞,服务器无法启动

@app.on_event("startup")
async def startup_event() -> None:
    """tasks to do at server startup"""
    fastapi.BackgroundTasks().add_task(Gatherer().start_metering_daemon)
Run Code Online (Sandbox Code Playgroud)

结果:如日志中观察到的,任务从未执行

@app.on_event("startup")
async def startup_event() -> None:
    """tasks to do at server startup"""
    fastapi.BackgroundTasks().add_task(asyncio.run, Gatherer().start_metering_daemon())
Run Code Online (Sandbox Code Playgroud)

结果:与上一结果相同

@app.on_event("startup")
async def startup_event() -> None:
    """tasks to do at server startup"""
    threading.Thread(target=asyncio.run, args=(Gatherer().start_metering_daemon(),)).start()
Run Code Online (Sandbox Code Playgroud)

结果:这个有效,但是 a) 没有意义;b) 为 N 个 Uvicorn 工作线程生成 N 个相同的线程,这些线程都将相同的数据写入数据库 N 次。

我现在已经没有解决方案了。我很确定我的问题一定有解决方案,因为这对我来说看起来很微不足道,但我找不到。

如果您想要更多背景信息,这里是我参考的项目的存储库。

小智 7

尝试

@app.on_event("startup")
async def startup_event() -> None:
    """tasks to do at server startup"""
    asyncio.create_task(Gatherer().start_metering_daemon())
Run Code Online (Sandbox Code Playgroud)

  • 这不起作用:(当您在该函数中进行其他异步操作时,它仍然会抛出:[2021-09-10 21:00:56 +0000] [1330] [CRITICAL] WORKER TIMEOUT (pid:1337) [2021- 09-10 21:00:56 +0000] [1330] [警告] pid 1337 的工作进程因信号 6 而终止 (4认同)