You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 16:27:42