Skip to content

Commit e649c4f

Browse files
dengwx2026claude
andauthored
feat: support configurable Ray temp directory (alibaba#693) (alibaba#694)
* feat: support configurable Ray temp directory (alibaba#693) Add temp_dir field to RayConfig to allow redirecting Ray's temporary data away from /tmp, avoiding disk space issues during runtime env setup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * add ray docs --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 408e7a1 commit e649c4f

File tree

5 files changed

+126
-0
lines changed

5 files changed

+126
-0
lines changed

docs/dev/operator/ray.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Ray Operator 开发文档
2+
3+
## Ray 临时目录配置 (`temp_dir`)
4+
5+
### 背景
6+
7+
Ray 默认使用 `/tmp/ray/` 作为临时目录,用于存储 session 数据、runtime environment 克隆(virtualenv 复制)等。当 `/tmp` 磁盘空间不足时,sandbox 创建会失败:
8+
9+
```
10+
shutil.Error: [Errno 28] No space left on device
11+
```
12+
13+
典型场景:Ray 在 `_clonevirtualenv.py` 中执行 `shutil.copytree` 将项目的 `.venv` 克隆到 `/tmp/ray/session_*/runtime_resources/pip/*/virtualenv/` 时,`/tmp` 空间耗尽。
14+
15+
### 设计方案
16+
17+
`RayConfig` 中新增 `temp_dir` 字段,通过 YAML 配置文件指定 Ray 临时目录,传递给 `ray.init(_temp_dir=...)` 参数。
18+
19+
#### 配置字段
20+
21+
| 字段 | 类型 | 默认值 | 说明 |
22+
|------|------|--------|------|
23+
| `temp_dir` | `str \| None` | `None` | Ray 临时数据目录,支持相对路径(自动解析为绝对路径)。`None` 时使用 Ray 默认值 `/tmp/ray` |
24+
25+
#### YAML 配置示例
26+
27+
```yaml
28+
ray:
29+
runtime_env:
30+
working_dir: ./
31+
pip: ./requirements_sandbox_actor.txt
32+
namespace: "rock-sandbox-test"
33+
temp_dir: ./tmp/ray # 相对路径,自动解析为项目绝对路径
34+
```
35+
36+
### 实现
37+
38+
#### 涉及文件
39+
40+
| 文件 | 变更内容 |
41+
|------|---------|
42+
| `rock/config.py` | `RayConfig` 新增 `temp_dir` 字段,`__post_init__` 中自动将相对路径解析为绝对路径 |
43+
| `rock/admin/core/ray_service.py` | `ray.init()` 和重连逻辑中传入 `_temp_dir=self._config.temp_dir` |
44+
| `tests/unit/conftest.py` | 测试 `ray.init()` 中传入 `_temp_dir=ray_config.temp_dir` |
45+
| `rock-conf/rock-test.yml` | 测试环境配置 `temp_dir: ./tmp/ray` |
46+
47+
#### 路径解析
48+
49+
`RayConfig.__post_init__` 使用 `Path.resolve()` 将相对路径转为绝对路径:
50+
51+
```python
52+
def __post_init__(self):
53+
if self.temp_dir:
54+
self.temp_dir = str(Path(self.temp_dir).resolve())
55+
```
56+
57+
这是因为 Ray 内部要求 `_temp_dir` 必须是绝对路径,否则抛出 `ValueError("temp_dir must be absolute path or None.")`。
58+
59+
#### ray.init 参数传递
60+
61+
`_temp_dir` 通过 `**kwargs` 传入 `ray.init()`,当值为 `None` 时等价于不传该参数,Ray 使用默认 `/tmp/ray`。
62+
63+
### 影响分析
64+
65+
#### 代码路径影响
66+
67+
| 代码路径 | 是否受影响 | 说明 |
68+
|----------|-----------|------|
69+
| `RayConfig` 数据类 | 是 | 新增字段,所有环境加载配置都经过此类 |
70+
| `RayService.init()` | 是 | admin 服务启动时的 `ray.init()` |
71+
| `RayService._reconnect_ray()` | 是 | Ray 重连时的 `ray.init()` |
72+
| 测试 `conftest.py` | 是 | 单元/集成测试的 `ray.init()` |
73+
74+
#### 各环境实际影响
75+
76+
| 环境 | 配置文件 | 是否配置 `temp_dir` | 实际行为变化 |
77+
|------|---------|-------------------|-------------|
78+
| test | `rock-test.yml` | `./tmp/ray` | Ray 临时目录改为项目下 `tmp/ray/` |
79+
| local | `rock-local.yml` | 未配置 | 无变化,`_temp_dir=None`,仍使用 `/tmp/ray` |
80+
| dev | `rock-dev.yml` | 未配置 | 无变化,`_temp_dir=None`,仍使用 `/tmp/ray` |
81+
82+
#### 向后兼容性
83+
84+
- `temp_dir` 默认为 `None`,传给 `ray.init(_temp_dir=None)` 等价于不传该参数
85+
- 未配置 `temp_dir` 的环境行为完全不变
86+
- 无需修改已有的部署配置
87+
88+
### 运维指南
89+
90+
#### 启用 temp_dir
91+
92+
在对应环境的 YAML 配置文件中添加:
93+
94+
```yaml
95+
ray:
96+
temp_dir: /data/ray/tmp # 生产环境建议使用绝对路径,指向大容量磁盘
97+
```
98+
99+
#### 清理旧 Ray 临时数据
100+
101+
```bash
102+
# 查看 /tmp/ray 占用空间
103+
du -sh /tmp/ray/
104+
105+
# 停止 Ray 后清理
106+
ray stop
107+
rm -rf /tmp/ray/session_*
108+
109+
# 重启 Ray
110+
ray start --head
111+
```
112+
113+
#### 注意事项
114+
115+
- `tmp/` 目录已在项目 `.gitignore` 中,不会被提交
116+
- 相对路径基于进程工作目录解析,确保启动 admin 服务时工作目录为项目根目录
117+
- 生产环境建议使用绝对路径,避免工作目录不一致导致的路径错误

rock-conf/rock-test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ ray:
33
working_dir: ./
44
pip: ./requirements_sandbox_actor.txt
55
namespace: "rock-sandbox-test"
6+
temp_dir: ./tmp/ray
67

78
warmup:
89
images:

rock/admin/core/ray_service.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def init(self):
2828
runtime_env=self._config.runtime_env,
2929
namespace=self._config.namespace,
3030
resources=self._config.resources,
31+
_temp_dir=self._config.temp_dir,
3132
)
3233
if self._config.ray_reconnect_enabled:
3334
self._setup_ray_reconnect_scheduler()
@@ -76,6 +77,7 @@ async def _reconnect_ray(self):
7677
runtime_env=self._config.runtime_env,
7778
namespace=self._config.namespace,
7879
resources=self._config.resources,
80+
_temp_dir=self._config.temp_dir,
7981
)
8082
self._ray_request_count = 0
8183
end_time = time.time()

rock/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ class RayConfig:
1818
runtime_env: dict = field(default_factory=dict)
1919
namespace: str = "xrl-sandbox"
2020
resources: dict | None = None
21+
temp_dir: str | None = None
2122
ray_reconnect_enabled: bool = field(default=False)
2223
ray_reconnect_interval_seconds: int = field(default=60 * 60 * 12)
2324
ray_reconnect_request_threshold: int = field(default=10 * 1024 * 1024)
2425
ray_reconnect_check_interval_seconds: int = field(default=60 * 10)
2526
ray_reconnect_wait_timeout_seconds: int = field(default=30)
2627

28+
def __post_init__(self):
29+
if self.temp_dir:
30+
self.temp_dir = str(Path(self.temp_dir).resolve())
31+
2732

2833
@dataclass
2934
class WarmupConfig:

tests/unit/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ def ray_init_shutdown(rock_config: RockConfig):
111111
namespace=ray_namespace,
112112
runtime_env=ray_config.runtime_env,
113113
resources=ray_config.resources,
114+
_temp_dir=ray_config.temp_dir,
114115
)
115116
yield
116117

0 commit comments

Comments
 (0)