Skip to content

Commit f0b3d11

Browse files
authored
Preserve scheduler share for remote worker paths
Preserve an existing scheduler-side AGI_CLUSTER_SHARE when remote Workers Data Path names a separate worker-visible mount target.\n\nValidated with focused runtime misc support tests.
1 parent 7e03bd9 commit f0b3d11

5 files changed

Lines changed: 71 additions & 4 deletions

File tree

docs/.docs_source_mirror_stamp.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
"file_count": 276,
33
"format_version": 1,
44
"managed_target": "docs/source",
5-
"source_digest_sha256": "8dd710f147ddc9b04c22300de5f726797ac7b477ad545bd3ee0ad21c7f0586fa",
5+
"source_digest_sha256": "794fcdd8b7c212d91475c7734f42230331d760eea439a424cc10874055e73595",
66
"source_hint": "../thales_agilab/docs/source",
77
"sync_tool": "tools/sync_docs_source.py",
8-
"target_digest_sha256": "8dd710f147ddc9b04c22300de5f726797ac7b477ad545bd3ee0ad21c7f0586fa"
8+
"target_digest_sha256": "794fcdd8b7c212d91475c7734f42230331d760eea439a424cc10874055e73595"
99
}

docs/source/distributed-workers.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ Before configuring distributed workers, make sure the environment is ready:
4141
root is ``AGI_CLUSTER_SHARE``; remote workers can see the same backing storage
4242
through an SSHFS mount at **Workers Data Path**. In cluster mode, do not rely
4343
on ``AGI_LOCAL_SHARE`` as a fallback.
44+
- For remote workers, **Workers Data Path** is the worker-visible mount target,
45+
not a request to rewrite the scheduler-side ``AGI_CLUSTER_SHARE``. If the
46+
scheduler already points ``AGI_CLUSTER_SHARE`` at an absolute share root, AGILAB
47+
keeps that root and passes the worker-side path separately.
4448
- The shared-path rule above applies to remote workers. For a local-only Dask
4549
cluster, where workers are ``127.0.0.1`` or ``localhost``, the scheduler and
4650
workers share the same local filesystem. ``AGI_CLUSTER_SHARE`` may therefore
@@ -306,7 +310,8 @@ Use these habits to keep distributed runs predictable:
306310
**Workers Data Path** as the worker-side SSHFS mount target. These paths may
307311
differ on mixed operating systems, for example a macOS scheduler path mounted
308312
under a Linux worker home directory, but they must expose the same backing
309-
storage after SSHFS is mounted.
313+
storage after SSHFS is mounted. Do not use **Workers Data Path** to replace a
314+
preconfigured scheduler share root.
310315
- Keep local-only and remote-worker clusters distinct. Local-only clusters can
311316
use a local ``AGI_CLUSTER_SHARE`` path directly; remote-worker clusters need a
312317
worker-visible shared mount target in **Workers Data Path**.

docs/source/troubleshooting.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ your server IP and adjust mount paths as needed. The default ``AGI_CLUSTER_SHARE
125125
``clustershare/<user>`` under ``$HOME``. For cluster-enabled apps, that path must be mounted
126126
and writable on every node: ``AgiEnv`` now fails fast instead of silently falling back
127127
to ``AGI_LOCAL_SHARE`` or ``$HOME/localshare``. Ensure the chosen path exists and is writable.
128+
In remote-worker mode, keep ``AGI_CLUSTER_SHARE`` as the scheduler-side share root and
129+
use **Workers Data Path** for the worker-visible SSHFS mount target; AGILAB preserves an
130+
existing scheduler share when those paths intentionally differ.
128131
If you override the default in a multi-user setup, keep one exported share root per user
129132
instead of pointing several operators at the same writable cluster-share directory.
130133
The example export below uses a ``nobody:nogroup`` ownership policy so every

src/agilab/core/agi-cluster/src/agi_cluster/agi_distributor/runtime/runtime_misc_support.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,22 @@ def _absolute_workers_data_share_root(
433433
return Path(os.path.normpath(str(share_root)))
434434

435435

436+
def _workers_data_path_can_rebind_env_share(
437+
env: Any,
438+
workers_data_path: str,
439+
) -> bool:
440+
current_share = str(getattr(env, "AGI_CLUSTER_SHARE", "") or "").strip()
441+
if not current_share:
442+
return True
443+
workers_share_abs = _absolute_workers_data_share_root(env, workers_data_path)
444+
current_share_abs = _absolute_workers_data_share_root(env, current_share)
445+
try:
446+
workers_share_abs.relative_to(current_share_abs)
447+
except ValueError:
448+
return False
449+
return True
450+
451+
436452
def _apply_workers_data_path_to_env(
437453
env: Any,
438454
workers_data_path: str | None,
@@ -442,6 +458,8 @@ def _apply_workers_data_path_to_env(
442458
share_text = str(workers_data_path).strip()
443459
if not share_text:
444460
return
461+
if not _workers_data_path_can_rebind_env_share(env, share_text):
462+
return
445463

446464
share_root_abs = _absolute_workers_data_share_root(env, share_text)
447465
env.AGI_CLUSTER_SHARE = share_text

src/agilab/core/test/test_agi_distributor_runtime_misc_support.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ def test_initialize_runtime_state_rebinds_manager_share_root_to_workflow_session
612612
workers_data_path=session_root,
613613
)
614614

615-
expected_root = Path("/home/agi") / session_root
615+
expected_root = (Path("/home/agi") / session_root).resolve(strict=False)
616616
assert agi_cls._workers_data_path == session_root
617617
assert env.AGI_CLUSTER_SHARE == session_root
618618
assert env.agi_share_path == session_root
@@ -624,6 +624,47 @@ def test_initialize_runtime_state_rebinds_manager_share_root_to_workflow_session
624624
assert env.envars["AGI_CLUSTER_SHARE"] == session_root
625625

626626

627+
def test_initialize_runtime_state_preserves_scheduler_share_for_remote_workers_path():
628+
agi_cls = SimpleNamespace()
629+
scheduler_share = Path("/home/agi/data")
630+
env = SimpleNamespace(
631+
manager_path=Path("/tmp/manager"),
632+
target="flight_trajectory_project",
633+
verbose=0,
634+
home_abs=Path("/home/agi"),
635+
AGI_CLUSTER_SHARE=str(scheduler_share),
636+
agi_share_path=str(scheduler_share),
637+
agi_share_path_abs=scheduler_share,
638+
_share_root_cache=scheduler_share,
639+
_share_target_name=lambda: "flight_trajectory",
640+
share_target_name="scheduler",
641+
app_data_rel=scheduler_share / "scheduler",
642+
dataframe_path=scheduler_share / "scheduler" / "dataframe",
643+
envars={"AGI_CLUSTER_SHARE": str(scheduler_share)},
644+
)
645+
646+
runtime_misc_support.initialize_runtime_state(
647+
agi_cls,
648+
env,
649+
workers={"192.168.20.15": 1},
650+
verbose=0,
651+
rapids_enabled=False,
652+
args={"data_in": "flight_trajectory/dataset"},
653+
worker_args={"data_in": "flight_trajectory/dataset"},
654+
workers_data_path="clustershare",
655+
)
656+
657+
assert agi_cls._workers_data_path == "clustershare"
658+
assert env.AGI_CLUSTER_SHARE == str(scheduler_share)
659+
assert env.agi_share_path == str(scheduler_share)
660+
assert env.agi_share_path_abs == scheduler_share
661+
assert env._share_root_cache == scheduler_share
662+
assert env.share_target_name == "scheduler"
663+
assert env.app_data_rel == scheduler_share / "scheduler"
664+
assert env.dataframe_path == scheduler_share / "scheduler" / "dataframe"
665+
assert env.envars["AGI_CLUSTER_SHARE"] == str(scheduler_share)
666+
667+
627668
def test_initialize_runtime_state_normalizes_windows_module_workers_data_path():
628669
agi_cls = SimpleNamespace()
629670
env = SimpleNamespace(

0 commit comments

Comments
 (0)