Skip to content

Commit b95a5ea

Browse files
thinkallCopilot
andcommitted
Force MLflow URI override in xdist workers to prevent yaml race
The previous attempt set MLFLOW_TRACKING_URI per-worker in pytest_configure, guarded by 'if MLFLOW_TRACKING_URI not in os.environ'. That guard hid a subtle bug: 1. The main pytest process runs pytest_configure first, sees the env var is unset, and exports file:///tmp/flaml_mlruns_main_PID. 2. xdist worker subprocesses (gw0, gw1) inherit that env var from the main process. 3. When each worker re-runs pytest_configure, the guard now evaluates to True (the var IS set), so workers skip the override and end up sharing the main process's tracking dir. 4. Concurrent writes from both workers to the same EXP/RUN/meta.yaml produce partial files, triggering 'yaml.parser.ParserError: while parsing a block mapping' in every subsequent FLAML+MLflow test on that worker. Fix: in xdist workers, force-override the URI when the inherited value is one we previously set (path contains 'flaml_mlruns_'); externally-set URIs (e.g. by the user) are still respected. The new per-worker path is 'flaml_mlruns_WORKER_PID'. Verified locally: 'pytest test/fabric/test_mlflow_coverage.py -n 2 --dist=loadfile' now creates per-worker dirs (flaml_mlruns_gw0_* distinct from main) and all 66 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8fba35a commit b95a5ea

1 file changed

Lines changed: 16 additions & 5 deletions

File tree

test/conftest.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,33 @@ def pytest_configure(config):
2222
# file. Concurrent writers can leave the file half-written, which then
2323
# surfaces as ``yaml.parser.ParserError: while parsing a block mapping``
2424
# in every subsequent test that talks to MLflow on the same worker.
25-
if "MLFLOW_TRACKING_URI" not in os.environ:
25+
#
26+
# ``pytest_configure`` runs in the main pytest process AND in every
27+
# xdist worker. The main process runs first and exports
28+
# ``MLFLOW_TRACKING_URI``; workers then inherit that value. Without
29+
# the override below, all workers would share the main process's
30+
# tracking dir and race on writes. We therefore force-override the
31+
# URI in xdist workers when the inherited value is one we previously
32+
# set ourselves (path contains ``flaml_mlruns_``); a URI set
33+
# externally by the user is left untouched.
34+
worker_id = os.environ.get("PYTEST_XDIST_WORKER")
35+
existing_uri = os.environ.get("MLFLOW_TRACKING_URI", "")
36+
inherited_from_main = bool(worker_id) and "flaml_mlruns_" in existing_uri
37+
if not existing_uri or inherited_from_main:
2638
import tempfile
39+
from pathlib import Path
2740

28-
worker_id = os.environ.get("PYTEST_XDIST_WORKER", "main")
41+
tag = worker_id or "main"
2942
# IMPORTANT: do NOT pre-create this directory. ``FileStore.__init__``
3043
# only bootstraps the default ``Experiment(id="0")`` (which several
3144
# tests in ``test/fabric/test_mlflow_coverage.py`` implicitly rely on
3245
# via ``mlflow.start_run()``) when the root directory does not yet
3346
# exist. Pre-creating the dir would leave the store without a
3447
# Default experiment, breaking those tests with
3548
# ``MlflowException: Could not find experiment with ID 0``.
36-
tracking_dir = os.path.join(tempfile.gettempdir(), f"flaml_mlruns_{worker_id}_{os.getpid()}")
49+
tracking_dir = os.path.join(tempfile.gettempdir(), f"flaml_mlruns_{tag}_{os.getpid()}")
3750
# ``file:`` URIs need POSIX-style forward slashes even on Windows;
3851
# ``Path.as_uri()`` handles the platform-specific prefix correctly.
39-
from pathlib import Path
40-
4152
os.environ["MLFLOW_TRACKING_URI"] = Path(tracking_dir).as_uri()
4253

4354

0 commit comments

Comments
 (0)