Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion recipe/simple_use_case/relax_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import transfer_queue as tq
from transfer_queue import RankAwareSampler, StreamingDataLoader, StreamingDataset
from transfer_queue.metadata import BatchMeta
from transfer_queue.utils.common import ray_namespace
from transfer_queue.utils.logging_utils import get_logger

logger = get_logger("MAIN", default_level="INFO")
Expand Down Expand Up @@ -131,7 +132,7 @@ class BaseStageWorker:
def __init__(self, tq_config, tracker, worker_id: int, config: "DemoConfig"):
tq.init(tq_config)
self.tq_client = tq.get_client()
controller = ray.get_actor("TransferQueueController", namespace="transfer_queue")
controller = ray.get_actor("TransferQueueController", namespace=ray_namespace())
self.cfg = ray.get(controller.get_config.remote())
self.tracker = tracker
self.worker_id = worker_id
Expand Down
5 changes: 3 additions & 2 deletions transfer_queue/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from transfer_queue.sampler import BaseSampler
from transfer_queue.storage.bootstrap import StorageBootstrapProvider
from transfer_queue.storage.managers.simple_storage_manager import AsyncSimpleStorageManager
from transfer_queue.utils.common import ray_namespace
from transfer_queue.utils.logging_utils import get_logger
from transfer_queue.utils.yuanrong_utils import cleanup_yuanrong_resources
from transfer_queue.utils.zmq_utils import process_zmq_server_info
Expand Down Expand Up @@ -123,7 +124,7 @@ def _init_from_existing() -> bool:
global _TQ_CONTROLLER
try:
if _TQ_CONTROLLER is None:
_TQ_CONTROLLER = ray.get_actor("TransferQueueController", namespace="transfer_queue")
_TQ_CONTROLLER = ray.get_actor("TransferQueueController", namespace=ray_namespace())

except ValueError:
logger.info("Called _init_from_existing() but TransferQueueController has not been initialized yet.")
Expand Down Expand Up @@ -207,7 +208,7 @@ def init(conf: DictConfig | None = None) -> DictConfig | None:
try:
global _TQ_CONTROLLER, _TQ_IS_OWNER
_TQ_CONTROLLER = TransferQueueController.options( # type: ignore[attr-defined]
name="TransferQueueController", namespace="transfer_queue"
name="TransferQueueController", namespace=ray_namespace()
).remote(sampler=sampler, polling_mode=final_conf.controller.polling_mode)
_TQ_IS_OWNER = True
logger.info("TransferQueueController has been created.")
Expand Down
6 changes: 3 additions & 3 deletions transfer_queue/kv_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from ray.exceptions import GetTimeoutError, RayActorError

from transfer_queue.lock_manager import _RESERVED_SLOTS, TransferQueueLockManager
from transfer_queue.utils.common import get_env_bool, get_node_round_robin_scheduling_strategies
from transfer_queue.utils.common import get_env_bool, get_node_round_robin_scheduling_strategies, ray_namespace

# Not asyncio.Lock: it is bound to one event loop and is not thread-safe, while a process
# may run several loops plus plain threads. A key is held exactly while it is in _table,
Expand Down Expand Up @@ -292,7 +292,7 @@ def _manager_name(shard: int) -> str:
def _lock_manager(shard: int):
if shard not in _managers:
try:
_managers[shard] = ray.get_actor(_manager_name(shard), namespace="transfer_queue")
_managers[shard] = ray.get_actor(_manager_name(shard), namespace=ray_namespace())
except ValueError:
raise RuntimeError(_NOT_INITIALIZED) from None
return _managers[shard]
Expand Down Expand Up @@ -556,7 +556,7 @@ def _start_lock_managers(settings: tuple[int, int] | None) -> None:
_owned = [
TransferQueueLockManager.options( # type: ignore[attr-defined]
name=_manager_name(shard),
namespace="transfer_queue",
namespace=ray_namespace(),
get_if_exists=True,
max_concurrency=max_waiting_acquires + _RESERVED_SLOTS,
scheduling_strategy=strategy,
Expand Down
5 changes: 3 additions & 2 deletions transfer_queue/storage/clients/ray_storage_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import torch

from transfer_queue.storage.clients.base import StorageClientFactory, StorageKVClient
from transfer_queue.utils.common import ray_namespace


@ray.remote(max_concurrency=8)
Expand Down Expand Up @@ -57,10 +58,10 @@ def __init__(self, config=None):

# initialize actor
try:
self.storage_actor = ray.get_actor("RayObjectRefStorage", namespace="transfer_queue")
self.storage_actor = ray.get_actor("RayObjectRefStorage", namespace=ray_namespace())
except ValueError:
self.storage_actor = RayObjectRefStorage.options(
name="RayObjectRefStorage", namespace="transfer_queue", get_if_exists=False
name="RayObjectRefStorage", namespace=ray_namespace(), get_if_exists=False
).remote()

def put(self, keys: list[str], values: list[Any]) -> list[Any] | None:
Expand Down
9 changes: 9 additions & 0 deletions transfer_queue/utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ def limit_pytorch_auto_parallel_threads(target_num_threads: int | None = None, i
)


def ray_namespace() -> str:
"""Ray namespace of the TransferQueue named actors.

Defaults to ``transfer_queue``, shared by every job on the Ray cluster (see #115). Set
``TQ_RAY_NAMESPACE`` in every process of a job to keep concurrent jobs apart.
"""
return os.environ.get("TQ_RAY_NAMESPACE") or "transfer_queue"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Route shipped controller lookups through the new namespace

When TQ_RAY_NAMESPACE is set for a run of the shipped streaming tutorial or relax demo, tq.init() now creates or attaches in that namespace, but a repo-wide namespace search still finds hard-coded namespace="transfer_queue" lookups in tutorial/06_streaming_dataloader.py:187 and recipe/simple_use_case/relax_demo.py:134. Those workers therefore either raise ValueError when the default namespace is empty or read another job's controller, defeating the advertised isolation; migrate these supported callers to ray_namespace() as well.

AGENTS.md reference: AGENTS.md:L17-L18

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fd8a05f: both lookups use ray_namespace().



def get_env_bool(env_key: str, default: bool = False) -> bool:
"""Robustly get a boolean from an environment variable."""
env_value = os.getenv(env_key)
Expand Down
3 changes: 2 additions & 1 deletion tutorial/06_streaming_dataloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
StreamingDataLoader,
StreamingDataset,
)
from transfer_queue.utils.common import ray_namespace # noqa: E402


def setup_transfer_queue():
Expand Down Expand Up @@ -184,7 +185,7 @@ def update_worker(
# Step 1: Create StreamingDataset
# This dataset integrates with TransferQueue and handles batch retrieval

controller = ray.get_actor("TransferQueueController", namespace="transfer_queue")
controller = ray.get_actor("TransferQueueController", namespace=ray_namespace())
config = ray.get(controller.get_config.remote())

dataset = StreamingDataset(
Expand Down
Loading