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

开启lazy-apps的uWSGI+Flask多进程下Timer全局变量同步问题求助

Solving uWSGI Lazy-Apps + Multi-Process Timer Variable Sync Issue

Hey there, you're totally right about the root cause: with lazy-apps = true, every uWSGI worker process loads your Flask app independently. That means each worker gets its own copy of global_var, and the @timer(60) runs separately in every process. That's why you see initial 1s and then diverging counts later on.

Since disabling lazy-apps isn't an option due to MongoDB and other exceptions, here are practical, worker-safe solutions to sync your counter without dropping to a single process:

1. Use uWSGI Shared Memory (Fast, Server-Local)

uWSGI has built-in shared memory support that lets all processes access the same variable directly. It's the fastest option for single-server setups:

import uwsgi
from uwsgidecorators import timer

# Initialize shared memory area (4 bytes is enough for a standard integer)
if uwsgi.masterpid() == uwsgi.worker_id():
    # Only the master process creates the shared area to avoid duplicates
    uwsgi.sharedarea_create(0, 4)
    uwsgi.sharedarea_set(0, 0, b'\x00\x00\x00\x00')  # Start counter at 0

@timer(60)
def foo():
    # Read current value from shared memory
    current_bytes = uwsgi.sharedarea_get(0, 0, 4)
    current_val = int.from_bytes(current_bytes, byteorder='little')
    
    # Increment and write back
    current_val += 1
    uwsgi.sharedarea_set(0, 0, current_val.to_bytes(4, byteorder='little'))
    
    print(current_val)

Pros: Blazing fast, no external dependencies.
Cons: Only works if all workers run on the same server.

2. Use Redis (Scalable, Distributed-Friendly)

If you might scale to multiple servers later, a centralized datastore like Redis handles atomic increments natively, eliminating race conditions entirely:

First, install the Redis client:

pip install redis

Then adjust your code:

import redis
from uwsgidecorators import timer

# Connect to your Redis instance (update host/port/password as needed)
redis_client = redis.Redis(host='localhost', port=6379, db=0)

@timer(60)
def foo():
    # Atomic increment operation guarantees no race conditions
    global_var = redis_client.incr('grace_counter')
    print(global_var)

Pros: Works across multiple servers, fully concurrency-safe.
Cons: Adds an external dependency (Redis server).

3. Offload the Timer to a uWSGI Mule Process

uWSGI's mule system lets you run isolated processes dedicated to background tasks. You can restrict your timer to run only in one mule, so there's no duplicate counter:

First, add a mule to your uwsgi.ini:

[uwsgi]
# ... your existing config ...
mule = 1  # Start one dedicated mule process

Then modify your code to target the mule:

from uwsgidecorators import timer, mule

# Only run this timer in the mule process
@mule
@timer(60)
def foo():
    global global_var
    global_var += 1
    print(global_var)

Pros: No external dependencies, keeps the counter isolated to a single process.
Cons: The mule doesn't handle web traffic, so it's only useful for background tasks.

4. File Lock + Local File (Simple, Low-Overhead)

If you want a no-frills solution without extra tools, a file with an exclusive lock works for small-scale apps:

import fcntl
from uwsgidecorators import timer

COUNTER_PATH = '/tmp/grace_counter.txt'

# Initialize counter file if it doesn't exist
try:
    with open(COUNTER_PATH, 'r'):
        pass
except FileNotFoundError:
    with open(COUNTER_PATH, 'w') as f:
        f.write('0')

@timer(60)
def foo():
    with open(COUNTER_PATH, 'r+') as f:
        # Acquire exclusive lock to prevent race conditions
        fcntl.flock(f, fcntl.LOCK_EX)
        
        # Read, increment, and write back
        current_val = int(f.read().strip())
        current_val += 1
        f.seek(0)
        f.write(str(current_val))
        f.truncate()
        
        print(current_val)

Pros: Dead simple, no extra dependencies.
Cons: Slower than shared memory/Redis, not ideal for high-frequency tasks.

All these solutions play nicely with lazy-apps = true—they either share state across processes or restrict the timer to a single process. Pick the one that fits your deployment size and performance needs!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:09:46