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

如何终止Flask服务器中运行的特定请求并支持ID管控?

Flask 请求动态终止方案

核心思路

通过**请求唯一标识(UUID)+ 线程终止信号(threading.Event)**实现安全终止指定请求,同时将标识存入数据库用于后续触发终止操作,全程不影响服务器运行和其他请求处理。

实现步骤

1. 数据库表设计

先创建存储请求追踪信息的表(示例用SQLite):

CREATE TABLE request_tasks (
    request_id TEXT PRIMARY KEY,
    thread_id INTEGER,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    status TEXT DEFAULT 'running' -- 状态值:running/terminating/terminated/completed
);

2. 线程追踪与ID存储

在Flask请求处理流程中,为每个请求生成唯一UUID作为标识,关联终止信号并将关键信息存入数据库:

from flask import Flask, jsonify
import threading
import uuid
import sqlite3
import time

app = Flask(__name__)
# 全局字典:映射请求ID到终止信号Event,用于快速查找
request_signals = {}

def get_db_connection():
    conn = sqlite3.connect('requests.db')
    conn.row_factory = sqlite3.Row
    return conn

def long_running_task(request_id, stop_event):
    conn = get_db_connection()
    try:
        # 模拟耗时任务,每30秒检查一次终止信号
        for _ in range(120):  # 对应1小时总耗时(120*30秒)
            if stop_event.is_set():
                # 更新任务状态为已终止
                conn.execute('UPDATE request_tasks SET status = ? WHERE request_id = ?', ('terminated', request_id))
                conn.commit()
                return
            # 此处替换为实际业务逻辑
            time.sleep(30)
        # 任务正常完成
        conn.execute('UPDATE request_tasks SET status = ? WHERE request_id = ?', ('completed', request_id))
        conn.commit()
    finally:
        conn.close()
        # 任务结束后清理全局字典,释放内存
        if request_id in request_signals:
            del request_signals[request_id]

@app.route('/start-task', methods=['POST'])
def start_task():
    request_id = str(uuid.uuid4())
    stop_event = threading.Event()
    # 绑定请求ID与终止信号
    request_signals[request_id] = stop_event
    # 获取当前请求线程ID
    thread_id = threading.get_ident()
    
    # 将请求信息存入数据库
    conn = get_db_connection()
    conn.execute('INSERT INTO request_tasks (request_id, thread_id) VALUES (?, ?)', (request_id, thread_id))
    conn.commit()
    conn.close()
    
    # 启动耗时任务(Flask多线程模式下,此视图函数本身运行在独立线程中)
    long_running_task(request_id, stop_event)
    return jsonify({'request_id': request_id, 'message': 'Task started'})

@app.route('/terminate-task/<request_id>', methods=['POST'])
def terminate_task(request_id):
    conn = get_db_connection()
    # 验证请求存在且处于运行状态
    task = conn.execute('SELECT * FROM request_tasks WHERE request_id = ? AND status = ?', (request_id, 'running')).fetchone()
    if not task:
        conn.close()
        return jsonify({'error': 'Task not found or already terminated/completed'}), 404
    
    # 发送终止信号
    if request_id in request_signals:
        stop_event = request_signals[request_id]
        stop_event.set()
        # 更新状态为终止中
        conn.execute('UPDATE request_tasks SET status = ? WHERE request_id = ?', ('terminating', request_id))
        conn.commit()
        conn.close()
        return jsonify({'message': 'Termination signal sent'})
    else:
        conn.close()
        return jsonify({'error': 'Task signal not found (may have completed)'}), 404

3. 关键注意事项

  • 禁止强制终止线程:绝对不要使用thread._stop()等危险方法,会引发资源泄漏、锁未释放等问题,必须通过任务内部定期检查终止信号实现优雅退出。
  • 内存与数据维护:任务完成/终止后,及时清理全局字典中的信号条目;定期归档或删除数据库中已完成的任务记录,避免数据冗余。
  • 跨重启处理:若需要服务器重启后仍能触发终止,需将终止信号状态存入数据库,重启后恢复信号映射逻辑(需额外开发适配)。

内容的提问来源于stack exchange,提问作者kp sutra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:33:15