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

如何让Flask后端响应前端AbortController的请求终止信号?

Flask+Gunicorn 耗时请求优雅取消方案

针对前端用AbortController发送终止信号后,后端仍在处理请求的问题,结合当前Flask、Werkzeug及Python的特性,以下是几个实用的解决方案:

一、关键节点检查连接状态(最通用)

Flask的请求对象可通过Werkzeug提供的环境变量或连接属性,检测客户端是否已断开连接。在耗时任务的循环或分批次处理节点中插入检查,一旦发现连接断开就终止任务。

示例代码:

from flask import Flask, request
import time
from sqlalchemy import create_engine

app = Flask(__name__)
db_engine = create_engine("your-db-url")

@app.route('/large-db-query')
def large_db_query():
    try:
        conn = db_engine.connect()
        # 分批次查询数据,避免一次性加载大量数据
        result_proxy = conn.execution_options(stream_results=True).execute("SELECT * FROM big_table")
        
        for batch in result_proxy.partitions(1000):
            # 优先使用官方标记检查连接状态
            if request.environ.get('werkzeug.request_disconnected') or not request.connection._sock:
                raise RuntimeError("客户端已取消请求")
            
            # 处理当前批次数据
            process_batch(batch)
        
        return {"status": "completed", "message": "数据处理完成"}
    except RuntimeError as e:
        # 强制清理资源:关闭数据库连接、释放游标等
        conn.close()
        app.logger.info(f"请求已取消:{str(e)}")
        return {"status": "cancelled"}, 499  # 499代表客户端主动关闭连接
    except Exception as e:
        conn.close()
        app.logger.error(f"处理出错:{str(e)}")
        return {"status": "error"}, 500

二、捕获SIGPIPE信号(针对进程级终止)

当客户端断开连接时,内核会给Gunicorn的工作进程发送SIGPIPE信号(管道破裂)。我们可以捕获这个信号,在处理函数中终止任务并清理资源。

示例代码:

from flask import Flask, request
import signal
import sys
import time

app = Flask(__name__)

def sigpipe_handler(signum, frame):
    # 执行资源清理:关闭数据库连接、释放文件句柄等
    app.logger.info("收到SIGPIPE信号,客户端已断开,终止任务")
    sys.exit(0)  # 终止当前工作进程,Gunicorn会自动重启新进程

# 注册SIGPIPE信号处理器
signal.signal(signal.SIGPIPE, sigpipe_handler)

@app.route('/cpu-heavy-task')
def cpu_heavy_task():
    try:
        # 模拟CPU密集型任务
        for i in range(10000000):
            _ = i ** 2
        return {"status": "completed"}
    except SystemExit:
        return {"status": "cancelled"}, 499
  • 适用场景:CPU密集型任务,无法在任务中插入连接检查的情况;注意终止进程会丢失当前进程状态,适合单请求占用大量资源的场景。

三、异步Flask + 可取消异步任务(推荐)

Flask 2.0+支持异步视图,结合asyncio的取消机制,可更优雅处理请求取消。当客户端断开连接时,Werkzeug会触发请求断开标记,主动抛出CancelledError即可终止异步任务。

示例代码:

from flask import Flask, request
import asyncio
import aiohttp

app = Flask(__name__)

@app.route('/async-external-call')
async def async_external_call():
    try:
        async with aiohttp.ClientSession() as session:
            # 模拟异步调用外部API或异步数据库查询
            for i in range(50):
                if request.environ.get('werkzeug.request_disconnected'):
                    raise asyncio.CancelledError
                
                async with session.get("https://api.example.com/data") as resp:
                    data = await resp.json()
                    process_data(data)
                
                await asyncio.sleep(0.2)
        
        return {"status": "completed"}
    except asyncio.CancelledError:
        app.logger.info("异步任务已被取消")
        return {"status": "cancelled"}, 499
  • 优势:异步场景下任务可及时终止,资源清理更灵活,且不会阻塞其他请求。

通用优化建议

  1. 分批次处理数据:无论同步还是异步,避免一次性查询或处理大量数据,分批次操作便于插入取消检查,还能降低内存占用。
  2. 资源强制清理:任务取消后必须手动清理数据库连接、文件句柄等资源,避免内存泄漏。
  3. Gunicorn配置配合:合理设置timeout(比如--timeout 30),确保长时间无响应的进程被自动回收,作为主动取消的补充。

内容的提问来源于stack exchange,提问作者Christina Stebbins

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 12:01:20