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

Flask请求中subprocess.Popen指定cwd并发场景偶发路径不存在异常求助

问题根因分析

你的问题核心是相对路径依赖进程全局工作目录 + Flask多线程并发下工作目录被篡改导致的,具体触发逻辑如下:

  • Flask默认以多线程模式处理请求,进程的当前工作目录是所有线程共享的全局变量
  • 你的_update是耗时逻辑,大概率内部存在os.chdir调用(比如生成zip包时切换到输出目录、操作临时文件时切换目录等)
  • 并发请求时,A请求执行到_update内部切换了工作目录,此时B请求刚好执行到subprocess.Popen步骤,传入的是相对路径./../../../client-repository,基于被篡改后的工作目录计算出来的路径自然不存在,就会抛出No such file or directory错误
  • 你打印repository_path的时候工作目录还没被修改,所以日志输出的路径是符合预期的,打印后到Popen执行前的窗口刚好被另一个线程修改了工作目录,才会出现日志和报错不一致的情况

解决方案

1. 优先将所有仓库路径替换为绝对路径(最高优先级,可解决90%以上该类问题)

在服务初始化、Unit对象赋值repository_path阶段,直接将相对路径转换为绝对路径存储,完全不依赖进程当前工作目录:

import os
# 赋值时提前转绝对路径
unit.repository_path = os.path.abspath("./../../../client-repository")

如果用pathlib的话可以用Path("./../../../client-repository").resolve()处理,效果一致。

2. 避免在业务逻辑中随意切换全局工作目录

如果确实需要临时切换目录,使用上下文管理器保证执行完立刻恢复原目录,且如果并发高的场景下需要加线程锁保证目录切换操作互斥:

import os
from threading import Lock

chdir_lock = Lock()

def safe_chdir(target_path):
    origin_path = os.getcwd()
    os.chdir(target_path)
    try:
        yield
    finally:
        os.chdir(origin_path)

# 业务中使用时加锁
with chdir_lock, safe_chdir("/path/to/zip/output"):
    # 执行生成zip等需要在指定目录执行的逻辑
    pass

3. 优化Popen写法避免潜在问题

你当前的Popen写法只消费stdout,未处理stderr,当git命令报错输出到stderr时缓冲区满会导致子进程挂死,建议修改为用communicate读取所有输出:

def get_latest_version(unit: Unit):
    repository_path = unit.repository_path
    branch = unit.branch

    print(f'repository_path: {repository_path}')
    try:
        with subprocess.Popen(["git", "rev-parse", branch],
                              cwd=repository_path,
                              universal_newlines=True,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE) as p:
            stdout, stderr = p.communicate()
            if p.returncode == 0:
                return stdout.strip()
            # 可打印stderr方便排查git本身的错误
            print(f"git command error: {stderr}")
    
    except Exception as e:
        print(f'Exception in popen: {e}')
    return None

4. 可选优化:添加版本结果缓存

如果允许返回几秒内的版本结果,可给get_latest_version加过期缓存,减少git命令调用次数,既提升性能也降低并发冲突概率。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 04:24:04