如何通过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)
部署步骤:
- 先启动Redis服务(确保它在后台稳定运行)
- 启动后台进程:
nohup python background_worker.py &(用nohup让它在后台运行) - 启动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
相关产品推荐
相关产品推荐

