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

如何通过uWSGI同时运行Flask应用与额外非应用进程?

部署带独立后台进程的Flask应用到uWSGI的正确姿势

嘿,我明白你遇到的问题了——当Flask应用里需要跑额外的后台进程(比如你代码里的AddP),直接用常规的uWSGI启动方式会踩坑:每个uWSGI worker都会初始化一遍全局的Manager和后台进程,导致重复进程满天飞,共享数据也容易出问题。下面给你几个靠谱的解决方案,从简单适配到生产环境级都有:

1. 用uWSGI钩子控制后台进程仅启动一次

uWSGI提供了钩子机制,可以让我们精准控制代码在哪个进程阶段执行。比如我们可以只让master进程初始化共享资源和后台进程,所有worker共享同一个实例:

先修改你的Flask代码:

from flask import Flask
from multiprocessing import Process, Manager
import time
import uwsgi
import os
from multiprocessing.managers import BaseManager

app = Flask(__name__)
ns = None

@app.route('/')
def index():
    return f"Current number is {ns.x}"

class AddP(Process):
    def __init__(self, ns):
        super().__init__()
        self.ns = ns
        # 设置为守护进程,uWSGI退出时会自动清理它
        self.daemon = True

    def run(self):
        # 模拟后台持续更新数据的逻辑
        while True:
            self.ns.x += 1
            time.sleep(1)

# 注册Manager类,方便worker连接
class MyManager(BaseManager):
    pass
MyManager.register('Namespace')

# 只在uWSGI的master进程初始化Manager和后台进程
if uwsgi.masterpid() == os.getpid():
    m = Manager(authkey=b'your_secure_key_here')
    ns = m.Namespace()
    ns.x = 0
    # 启动后台进程
    p = AddP(ns)
    p.start()
    # 把Manager的地址写入临时文件,供worker读取
    with open('/tmp/manager_addr.txt', 'w') as f:
        f.write(str(m._address))
else:
    # worker进程读取地址并连接到同一个Manager
    with open('/tmp/manager_addr.txt', 'r') as f:
        addr = eval(f.read())
    m = MyManager(address=addr, authkey=b'your_secure_key_here')
    m.connect()
    ns = m.Namespace()

启动uWSGI的时候必须开启master进程,不然钩子逻辑不生效:

uwsgi --master --http :5000 --module your_app_module --callable app --processes 4

2. 生产环境推荐:完全分离后台进程与Flask应用

如果你的后台逻辑比较复杂,或者追求更高的稳定性,最好把后台进程做成独立服务,用共享存储(比如Redis)来传递数据,彻底和Flask解耦:

Flask应用代码(app.py)

from flask import Flask
import redis

app = Flask(__name__)
# 连接Redis作为共享存储
r = redis.Redis(host='localhost', port=6379, db=0)

@app.route('/')
def index():
    # 获取当前值,默认0
    current_x = r.get('x') or b'0'
    return f"Current number is {int(current_x.decode())}"

后台进程代码(background_worker.py)

import redis
import time

r = redis.Redis(host='localhost', port=6379, db=0)
# 初始化值
r.set('x', 0)

# 持续更新数据
while True:
    r.incr('x')
    time.sleep(1)

部署步骤:

  1. 先启动Redis服务(确保它在后台稳定运行)
  2. 启动后台进程:nohup python background_worker.py &(用nohup让它在后台运行)
  3. 启动uWSGI部署Flask:uwsgi --http :5000 --module app --callable app --processes 4

这种方式的好处是:后台进程和Flask应用互不影响,哪怕Flask重启或者扩容worker,后台进程也不受干扰;而且Redis比multiprocessing.Manager更稳定,适合生产环境。

避坑提醒

  • 绝对不要在全局作用域直接启动后台进程!不然每个uWSGI worker都会创建一个重复的进程,资源浪费不说,共享数据还会乱套。
  • 如果用multiprocessing.Manager,一定要确保所有worker连接同一个Manager实例,不然会出现多个独立的共享空间。
  • 后台进程记得设为守护进程(daemon=True),不然uWSGI退出后,后台进程会变成孤儿进程留在系统里。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:31:46