TNOT commited on
Commit
412440a
·
1 Parent(s): 984676c

fix: MFA 数据目录隔离

Browse files
Files changed (1) hide show
  1. src/mfa_runner.py +50 -3
src/mfa_runner.py CHANGED
@@ -79,8 +79,13 @@ def _get_mfa_command() -> list:
79
  return ["mfa"]
80
 
81
 
82
- def _build_mfa_env() -> dict:
83
- """构造 MFA 专用环境变量"""
 
 
 
 
 
84
  env = os.environ.copy()
85
 
86
  if IS_WINDOWS:
@@ -93,6 +98,11 @@ def _build_mfa_env() -> dict:
93
  ]
94
  env["PATH"] = ";".join(mfa_paths) + ";" + env.get("PATH", "")
95
  else:
 
 
 
 
 
96
  # Linux: 设置 pkuseg 模型目录(云端使用持久化路径)
97
  persistent_models = Path("/home/studio_service/models")
98
  if persistent_models.exists():
@@ -164,6 +174,36 @@ def _clean_dict_empty_lines(dict_path: str) -> int:
164
  return 0
165
 
166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  def run_mfa_alignment(
168
  corpus_dir: str,
169
  output_dir: str,
@@ -197,6 +237,10 @@ def run_mfa_alignment(
197
  if progress_callback:
198
  progress_callback(msg)
199
 
 
 
 
 
200
  # 检查环境
201
  if not check_mfa_available():
202
  platform_hint = "tools/mfa_engine 目录" if IS_WINDOWS else "pip install montreal-forced-aligner"
@@ -254,7 +298,7 @@ def run_mfa_alignment(
254
  log(f"输出目录: {output_dir}")
255
 
256
  try:
257
- env = _build_mfa_env()
258
 
259
  result = subprocess.run(
260
  cmd,
@@ -295,6 +339,9 @@ def run_mfa_alignment(
295
  shutil.rmtree(temp_dir)
296
  except Exception:
297
  pass
 
 
 
298
 
299
 
300
  def run_mfa_validate(
 
79
  return ["mfa"]
80
 
81
 
82
+ def _build_mfa_env(mfa_root: Optional[Path] = None) -> dict:
83
+ """
84
+ 构造 MFA 专用环境变量
85
+
86
+ 参数:
87
+ mfa_root: 会话独立的 MFA 数据目录(用于并发隔离)
88
+ """
89
  env = os.environ.copy()
90
 
91
  if IS_WINDOWS:
 
98
  ]
99
  env["PATH"] = ";".join(mfa_paths) + ";" + env.get("PATH", "")
100
  else:
101
+ # Linux: 设置会话独立的 MFA_ROOT_DIR(解决并发数据库冲突)
102
+ if mfa_root:
103
+ env["MFA_ROOT_DIR"] = str(mfa_root)
104
+ logger.info(f"设置会话独立 MFA_ROOT_DIR: {mfa_root}")
105
+
106
  # Linux: 设置 pkuseg 模型目录(云端使用持久化路径)
107
  persistent_models = Path("/home/studio_service/models")
108
  if persistent_models.exists():
 
174
  return 0
175
 
176
 
177
+ def _create_isolated_mfa_root(session_id: str) -> Path:
178
+ """
179
+ 为每个会话创建独立的 MFA_ROOT_DIR,避免多用户并发时数据库冲突
180
+
181
+ MFA 使用 MFA_ROOT_DIR 环境变量指定数据目录,包含:
182
+ - pretrained_models/: 预训练模型缓存
183
+ - 各种 .db 文件: SQLite 数据库
184
+
185
+ 通过为每个会话创建独立目录,完全隔离并发用户
186
+ """
187
+ import tempfile
188
+
189
+ # 在系统临时目录下创建会话专属的 MFA 根目录
190
+ mfa_root = Path(tempfile.gettempdir()) / f"mfa_session_{session_id}"
191
+ mfa_root.mkdir(parents=True, exist_ok=True)
192
+
193
+ logger.info(f"创建会话独立 MFA 目录: {mfa_root}")
194
+ return mfa_root
195
+
196
+
197
+ def _cleanup_isolated_mfa_root(mfa_root: Path):
198
+ """清理会话独立的 MFA 目录"""
199
+ if mfa_root and mfa_root.exists() and "mfa_session_" in str(mfa_root):
200
+ try:
201
+ shutil.rmtree(mfa_root)
202
+ logger.info(f"已清理会话 MFA 目录: {mfa_root}")
203
+ except Exception as e:
204
+ logger.warning(f"清理会话 MFA 目录失败: {e}")
205
+
206
+
207
  def run_mfa_alignment(
208
  corpus_dir: str,
209
  output_dir: str,
 
237
  if progress_callback:
238
  progress_callback(msg)
239
 
240
+ # 为本次会话创建独立的 MFA 数据目录(并发安全)
241
+ session_id = uuid.uuid4().hex[:8]
242
+ isolated_mfa_root = _create_isolated_mfa_root(session_id) if not IS_WINDOWS else None
243
+
244
  # 检查环境
245
  if not check_mfa_available():
246
  platform_hint = "tools/mfa_engine 目录" if IS_WINDOWS else "pip install montreal-forced-aligner"
 
298
  log(f"输出目录: {output_dir}")
299
 
300
  try:
301
+ env = _build_mfa_env(isolated_mfa_root)
302
 
303
  result = subprocess.run(
304
  cmd,
 
339
  shutil.rmtree(temp_dir)
340
  except Exception:
341
  pass
342
+ # 清理会话独立的 MFA 数据目录
343
+ if isolated_mfa_root:
344
+ _cleanup_isolated_mfa_root(isolated_mfa_root)
345
 
346
 
347
  def run_mfa_validate(