如何在FastAPI中启动响应返回后不终止的后台进程,解决GitHub WebHook超时问题
如何在FastAPI WebHook中后台运行耗时命令,避免GitHub请求超时?
问题描述
我正在编写一个WebHook服务器,用于在Git仓库有推送操作时接收更新。收到GitHub发送的POST请求后,我需要执行git pull、mvn install等耗时较长的命令,但GitHub的WebHook请求会在10秒后超时。我的代码如下:
import logging import os from fastapi import FastAPI app = FastAPI() logger = logging.getLogger("uvicorn") def exec_cmd(command): out = os.system(command) logger.info(str(out)) @app.post('/') def func(): logger.info("WebHook received") exec_cmd("git pull") exec_cmd("mvn clean install") exec_cmd("killall java") return {} if __name__ == "__main__": import uvicorn exec_cmd("git pull") uvicorn.run("main:app", debug=False, reload=False, host="0.0.0.0")
我尝试将exec_cmd()改为异步函数,但发现当请求返回后,exec_cmd()无法运行至完成。请问该如何实现后台运行这些耗时任务,尽快响应GitHub的请求?
解决方案
方法1:使用Python线程(最适合你的场景)
由于你执行的是阻塞式的shell命令(比如mvn install这类CPU/IO密集型任务),用Python的threading模块把这些任务放到后台线程执行是最简单有效的方式。这样FastAPI接口可以立刻返回响应给GitHub,线程则在后台继续完成所有部署任务。
修改后的代码如下:
import logging import os import threading import subprocess from fastapi import FastAPI app = FastAPI() logger = logging.getLogger("uvicorn") def exec_cmd(command): # 用subprocess替代os.system,能捕获更详细的输出和错误信息 try: result = subprocess.run( command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) logger.info(f"Command '{command}' executed successfully:\n{result.stdout.strip()}") except subprocess.CalledProcessError as e: logger.error(f"Command '{command}' failed (exit code {e.returncode}):\n{e.stderr.strip()}") def background_deployment(): logger.info("Starting background deployment tasks...") exec_cmd("git pull") exec_cmd("mvn clean install") exec_cmd("killall java") logger.info("All background deployment tasks completed!") @app.post('/') def handle_webhook(): logger.info("GitHub WebHook request received") # 启动后台线程执行部署任务,daemon=True表示线程随主进程退出而结束 threading.Thread(target=background_deployment, daemon=True).start() # 立刻返回响应,避免GitHub超时 return {"status": "accepted", "message": "Deployment started in background"} if __name__ == "__main__": import uvicorn exec_cmd("git pull") uvicorn.run("main:app", debug=False, reload=False, host="0.0.0.0")
为什么异步函数不适用?
FastAPI的异步函数是基于事件循环的,适合IO密集型的非阻塞操作(比如HTTP请求),但对于git pull、mvn install这类阻塞式的shell命令,异步函数并不会真正让任务在后台运行——事件循环会被阻塞,而且当接口返回响应后,事件循环可能会终止未完成的任务,导致你的部署流程中断。线程则完全独立于FastAPI的请求处理流程,能保证任务执行完成。
进阶方案:使用任务队列(可选)
如果你的部署需求更复杂(比如需要任务重试、状态追踪、分布式执行),可以考虑用Celery配合Redis或RabbitMQ作为消息队列。不过对于简单的WebHook场景,线程方案已经足够轻量和好用了。
内容的提问来源于stack exchange,提问作者Rumesh Madhusanka
相关产品推荐
相关产品推荐

