使用asyncio.create_task启动uvicorn.serve()始终仅单worker的问题排查
问题原因
当你直接实例化uvicorn.Server并调用serve()方法时,workers参数会被完全忽略。Uvicorn的多worker模式由顶层进程管理逻辑处理,仅在通过命令行启动或调用uvicorn.run()函数(而非直接操作Server类)时,才会触发多进程worker的创建。直接使用Server类启动时,无论设置多少workers值,都只会运行单进程模式。
另外需要注意:若强行启用多worker,你的Rocketry调度器会在每个worker进程中启动一个实例,大概率导致任务重复执行。
解决方案1:改用uvicorn.run()启动(推荐)
如果不需要保留自定义Server的退出逻辑,直接使用uvicorn.run()即可让workers参数生效:
import asyncio import uvicorn from core.deps import app as app_fastapi from app.scheduler import app as app_rocketry async def start_scheduler(): await app_rocketry.serve() if __name__ == "__main__": # 在主事件循环启动调度器后台任务 loop = asyncio.get_event_loop() loop.create_task(start_scheduler()) # uvicorn.run会正确处理多worker创建 uvicorn.run(app_fastapi, workers=4, loop='asyncio')
注意:多worker模式下每个进程都会启动Rocketry,若需避免任务重复,建议将Rocketry作为独立服务启动,或使用Rocketry的分布式锁机制。
解决方案2:手动管理多worker进程(保留自定义Server逻辑)
若必须保留自定义的Server类(比如需要在退出时关闭Rocketry),可通过multiprocessing手动创建多个worker进程:
import asyncio import multiprocessing import uvicorn from core.deps import app as app_fastapi from app.scheduler import app as app_rocketry class Server(uvicorn.Server): def handle_exit(self, sig: int, frame) -> None: app_rocketry.session.shut_down() return super().handle_exit(sig, frame) def run_worker(): # 每个worker进程启动独立的Server实例 server = Server(config=uvicorn.Config(app_fastapi, loop='asyncio')) asyncio.run(server.serve()) async def main(): # 仅在主进程启动一次Rocketry,避免任务重复 scheduler_task = asyncio.create_task(app_rocketry.serve()) # 创建并启动4个worker进程 workers = [] for _ in range(4): p = multiprocessing.Process(target=run_worker) p.start() workers.append(p) # 等待调度器运行结束,或按需监控worker状态 await scheduler_task # 退出时关闭所有worker进程 for p in workers: p.terminate() p.join() if __name__ == "__main__": asyncio.run(main())
额外注意事项
- 多worker进程相互隔离,若应用依赖内存共享状态(如缓存),需使用Redis等外部存储同步数据。
- 若Rocketry需与FastAPI共享数据,同样要依赖外部存储,避免进程间数据不一致。
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

