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

Flask如何在用户关闭浏览器重开后仍保留后台进度处理进程

解决方案

核心问题本质

你遇到的问题根源是计算任务与Flask Web请求的生命周期强绑定:默认WSGI服务器在检测到客户端(浏览器)断开连接后,会中断当前正在处理的请求对应的进程/线程;同时任务状态没有和用户唯一标识做持久化绑定,用户重新打开页面后无法关联到之前运行的任务。
下面是可落地、支持多用户扩展的生产级方案:

方案实现步骤

1. 解耦计算任务与Web进程

用异步任务队列托管所有计算任务,完全脱离Flask Web请求的生命周期,哪怕浏览器断开连接、Web服务重启,任务都能正常运行。
Python生态最常用的组合是 Celery + Redis/RabbitMQ:

  • Celery 负责任务调度、执行、状态管理
  • Redis/RabbitMQ 作为消息中间件存储任务队列,同时可用来缓存进度数据

2. 任务与用户唯一标识绑定

所有计算任务触发时,生成唯一的任务ID,和当前登录用户的唯一标识(比如用户ID,存在登录态Session/JWT中)绑定,持久化存储到数据库/Redis中,支持一个用户同时跑多个任务的场景。

3. 调整相关代码实现

首先配置Celery

from celery import Celery
from flask import Flask, session, request

app = Flask(__name__)
# 配置Celery,用Redis做中间件和结果存储
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'

celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)

写计算任务逻辑,支持进度更新

@celery.task(bind=True)
def your_calculation_task(self, user_id, *task_params):
    total_steps = 100 # 按你的计算逻辑修改总步数
    for step in range(total_steps):
        # 你的计算逻辑
        # ...
        # 更新进度,Celery会自动存储状态
        self.update_state(state='PROGRESS', meta={'current': step+1, 'total': total_steps, 'percentage': (step+1)/total_steps*100})
        # 也可以同步把进度写到你原来的DB,兼容已有逻辑
        # write_progress_to_db(user_id, self.request.id, (step+1)/total_steps*100)
    return {'status': 'success', 'result': '你的计算结果'}

新增计算任务触发接口

@app.route("/start_calculation", methods=['POST'])
def start_calc():
    user_id = session.get('user_id') # 取当前登录用户的唯一ID
    if not user_id:
        return "请先登录", 401
    # 启动异步任务
    task = your_calculation_task.delay(user_id)
    # 把任务ID和用户ID绑定存储到DB/Redis
    # bind_task_to_user(user_id, task.id)
    return {"task_id": task.id}

调整进度查询接口

@app.route("/progress")
def check_progress():
    user_id = session.get('user_id')
    if not user_id:
        return "请先登录", 401
    # 可查当前用户对应的正在运行的任务ID,也可由前端传指定task_id查询多个任务
    # task_id = get_user_running_task(user_id)
    task_id = request.args.get('task_id')
    if not task_id:
        return {"percentage": 0, "has_running_task": False}
    task = your_calculation_task.AsyncResult(task_id)
    if task.state == 'PENDING':
        progress = 0
    elif task.state == 'PROGRESS':
        progress = task.info.get('percentage', 0)
    elif task.state == 'SUCCESS':
        progress = 100
    else: # 失败/取消等异常状态
        progress = -1
    return {"percentage": progress, "task_state": task.state}

首页加载逻辑调整

@app.route("/home_page")
def load_home_page_details():
    user_id = session.get('user_id')
    home_data = load_projects_home()
    # 额外返回当前用户有没有正在运行的任务,前端如果检测到有,自动开始拉取进度
    # running_task = get_user_running_task(user_id)
    # home_data['running_task_id'] = running_task.id if running_task else None
    return home_data

4. 部署注意事项

  • 不要用Flask自带的开发服务器部署生产环境,改用Gunicorn/uWSGI等生产级WSGI服务器
  • Celery Worker需要单独启动,可根据业务量增加多个Worker节点,天然支持水平扩展
  • 中间件和存储层用集群部署的话,可支撑十万级以上用户同时跑任务

方案优势

  • 完全解耦计算任务和Web请求,浏览器关闭/断开连接完全不影响任务运行
  • 任务和用户ID绑定,用户重新登录后可以直接找回之前的任务进度
  • 架构支持水平扩展,Celery、中间件、存储都可以集群部署,适配多用户大流量场景

内容的提问来源于stack exchange,提问作者Danish Xavier

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 14:06:04