Skip to content

Commit 5048aeb

Browse files
authored
Feature/code refine (#56)
* Refactor HTTP/2 transport to use builder pattern for remote transport creation - Updated `Http2RemoteTransport` to utilize a builder pattern, enhancing flexibility in specifying transport targets (by name, ID, or hierarchical path). - Introduced `TransportTarget` enum to clearly define the target type for remote actors. - Refactored related code in `ActorSystem` to align with the new transport creation method, improving readability and maintainability. - Enhanced tests to validate the new builder functionality and ensure correct behavior across various transport scenarios. * Refactor Pulsing framework for improved actor management and API clarity - Removed unused imports and refactored actor service references in `__init__.py` for better readability. - Consolidated actor service registration in `actor_system` to enhance clarity and maintainability. - Streamlined the `Remote` API in `router.py` by introducing a helper method for chunk building, reducing code duplication. - Updated `RustSchedulerBase` and its subclasses to improve worker selection logic and enhance code organization. - Refactored `StorageManager` to simplify bucket and topic management, improving locking mechanisms and resource handling. - Enhanced `SyncQueue` and `SyncQueueReader` to utilize a common synchronous execution method, improving code consistency. - Updated tests to reflect changes in actor proxy handling and ensure robust functionality across various scenarios. * Refactor Pulsing framework to enhance API clarity and actor management - Removed unused imports and consolidated actor service references in `__init__.py` for improved readability. - Updated `_GlobalQueueAPI` and `_GlobalTopicAPI` to utilize direct queue and topic writing/reading functions, enhancing clarity. - Introduced new `protocol.py` and `proxy.py` files to encapsulate message serialization and actor proxy functionalities, streamlining the codebase. - Refactored `remote.py` to remove redundant methods and improve organization, focusing on actor lifecycle management. - Enhanced `service.py` with a dedicated `PythonActorService` for better actor creation handling and improved error management. - Updated documentation and tests to reflect changes in actor management and API structure, ensuring robust functionality. * Refactor Python API documentation for Pulsing framework - Streamlined the Python API documentation by reorganizing sections for clarity, including lifecycle management, actor definition, and usage examples. - Enhanced actor management details, including initialization, spawning, and resolution methods, to improve user understanding. - Updated examples to reflect new API structures and best practices, ensuring consistency and clarity in usage. - Removed outdated sections and consolidated information to provide a more cohesive and user-friendly documentation experience. * Enhance Pulsing framework's actor resolution and documentation - Updated the `resolve` function to support typed proxies, allowing for direct method calls without needing to use `.as_type()` or `.as_any()`. - Improved documentation across multiple files to clarify the usage of `pul.resolve()` for both typed and untyped proxies, enhancing user understanding. - Refactored examples to demonstrate the new resolution capabilities and best practices for actor management. - Consolidated references to actor resolution methods in the API documentation, ensuring consistency and clarity for users transitioning from previous versions.
1 parent 33cf758 commit 5048aeb

77 files changed

Lines changed: 4364 additions & 4902 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CONTRIBUTING.md

Lines changed: 116 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,169 @@
11
# Contributing to Pulsing
22

3-
感谢你对 Pulsing 的兴趣!我们欢迎各种形式的贡献
3+
感谢你对 Pulsing 的贡献兴趣!本文档介绍如何搭建开发环境、运行测试以及提交代码
44

5-
## 开发环境设置
5+
## 前置要求
66

7-
### 前置要求
7+
| 工具 | 版本 | 安装方式 |
8+
|------|------|----------|
9+
| Rust | ≥ 1.75 | `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \| sh` |
10+
| Python | ≥ 3.10 | [python.org](https://python.org)`uv python install 3.11` |
11+
| uv | 最新 | `curl -LsSf https://astral.sh/uv/install.sh \| sh` |
12+
| just | 最新 | `cargo install just``brew install just` |
813

9-
- Rust 1.75+
10-
- Python 3.10+
11-
- maturin (`pip install maturin`)
12-
13-
### 构建项目
14+
## 快速开始(三步)
1415

1516
```bash
16-
# 克隆仓库
17-
git clone https://github.com/DeepLink-org/Pulsing.git
18-
cd pulsing
19-
20-
# 安装 Python 依赖
21-
pip install -e .
22-
# 或使用 maturin
23-
maturin develop
24-
25-
# 运行测试
26-
cargo test
27-
pytest tests/
28-
```
17+
# 1. 克隆仓库
18+
git clone https://github.com/DeepLink-org/Pulsing.git && cd Pulsing
2919

30-
## 贡献流程
20+
# 2. 创建并激活 Python 虚拟环境,安装开发依赖
21+
uv sync --extra dev
3122

32-
### 1. 创建 Issue
33-
34-
在开始工作之前,请先创建一个 Issue 讨论你想要做的改动。这有助于避免重复工作并确保你的贡献与项目方向一致。
23+
# 3. 编译 Rust 核心并安装到当前环境
24+
uv run maturin develop
25+
```
3526

36-
### 2. Fork 和 Clone
27+
完成后可以验证安装:
3728

3829
```bash
39-
git clone https://github.com/YOUR_USERNAME/pulsing.git
40-
cd pulsing
41-
git remote add upstream https://github.com/DeepLink-org/Pulsing.git
30+
uv run python -c "import pulsing; print(pulsing.__version__)"
4231
```
4332

44-
### 3. 创建分支
33+
## 常用开发命令
34+
35+
项目使用 [just](https://github.com/casey/just) 作为任务运行器,所有常用命令都在 `Justfile` 中定义。
4536

4637
```bash
47-
git checkout -b feature/your-feature-name
48-
#
49-
git checkout -b fix/your-fix-name
38+
just dev # 编译并安装(开发模式,等同于 maturin develop)
39+
just test # 运行全部测试(Rust + Python)
40+
just test-python # 仅运行 Python 测试
41+
just test-rust # 仅运行 Rust 测试
42+
just fmt # 格式化代码(Rust + Python)
43+
just lint # 代码检查
44+
just check # 提交前完整检查(格式 + lint + 测试)
45+
just cov # 生成覆盖率报告
46+
just clean # 清理构建产物
5047
```
5148

52-
### 4. 开发
49+
> **提示**:提交代码前请运行 `just check`,确保所有检查通过。
5350
54-
- 遵循现有的代码风格
55-
- 添加必要的测试
56-
- 更新相关文档
51+
## 项目结构
5752

58-
### 5. 提交
53+
```
54+
Pulsing/
55+
├── crates/
56+
│ ├── pulsing-actor/ # Rust 核心:Actor、Cluster、Transport
57+
│ └── pulsing-py/ # PyO3 绑定:将 Rust 类型暴露给 Python
58+
├── python/pulsing/ # Python 包
59+
│ ├── core/ # @remote 装饰器、ActorProxy
60+
│ ├── serving/ # LLM 服务路由、调度
61+
│ ├── streaming/ # 分布式队列与发布/订阅
62+
│ ├── agent/ # Agent 运行时工具
63+
│ └── integrations/ # Ray / AutoGen / LangGraph 集成
64+
├── tests/python/ # Python 测试
65+
├── examples/ # 示例代码
66+
└── docs/ # 文档(MkDocs)
67+
```
5968

60-
我们使用 [Conventional Commits](https://www.conventionalcommits.org/) 规范:
69+
## 开发工作流
6170

71+
### 修改 Python 代码
72+
73+
Python 代码无需重新编译,修改后直接运行测试:
74+
75+
```bash
76+
just test-python
77+
# 或者运行单个文件
78+
uv run pytest tests/python/test_remote_decorator.py -v
6279
```
63-
feat: 添加新功能
64-
fix: 修复 bug
65-
docs: 更新文档
66-
test: 添加或修改测试
67-
refactor: 代码重构
68-
chore: 构建过程或辅助工具的变动
69-
```
7080

71-
示例:
81+
### 修改 Rust 代码
82+
83+
修改 Rust 代码后需要重新编译:
84+
7285
```bash
73-
git commit -m "feat: add streaming support to ActorRef"
74-
git commit -m "fix: resolve memory leak in mailbox"
75-
git commit -m "docs: update README with new examples"
86+
just dev
87+
just test
7688
```
7789

78-
### 6. 提交 PR
90+
### 添加新特性
7991

80-
- 确保所有测试通过
81-
- 确保代码格式正确 (`cargo fmt`, `ruff format`)
82-
- 提供清晰的 PR 描述
92+
1.`crates/pulsing-actor/` 实现 Rust 逻辑
93+
2.`crates/pulsing-py/src/` 添加 PyO3 绑定
94+
3.`python/pulsing/` 添加 Python 封装(如需要)
95+
4.`tests/python/` 添加测试
96+
5. 运行 `just check` 确认无误
8397

84-
## 代码风格
98+
## 代码规范
8599

86100
### Rust
87101

88-
- 使用 `cargo fmt` 格式化代码
89-
- 使用 `cargo clippy` 检查代码质量
90-
- 遵循 [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/)
102+
- 使用 `cargo fmt` 格式化(`just fmt` 会自动运行)
103+
- 通过 `cargo clippy` 检查(`just lint` 会自动运行)
104+
- 公共 API 必须有文档注释(`///`
105+
- 错误类型使用 `thiserror` 定义,避免使用 `anyhow` 做为库的公共 API
91106

92107
### Python
93108

94-
- 使用 `ruff` 进行格式化和检查
95-
- 遵循 PEP 8
96-
- 使用类型注解
109+
- 使用 `ruff format` 格式化(行宽 88)
110+
- 使用 `ruff check` 检查(遵循 E/F/W/I/UP/B 规则集)
111+
- 类型注解尽量完整
112+
- 异步函数优先使用 `async def`
97113

98-
## 测试
114+
### 测试
99115

100-
### Rust 测试
116+
- Python 测试使用 `pytest-asyncio`,配置 `asyncio_mode = "auto"`
117+
- 测试函数命名:`test_<功能描述>_<场景>`
118+
- 避免测试间共享全局状态(每个测试通过 fixture 独立初始化系统)
119+
120+
## 运行文档
101121

102122
```bash
103-
# 运行所有测试
104-
cargo test
123+
cd docs
124+
uv run mkdocs serve
125+
# 访问 http://localhost:8000
126+
```
105127

106-
# 运行特定测试
107-
cargo test test_name
128+
## 提交 PR
108129

109-
# 运行 Actor System 测试
110-
cargo test -p pulsing-actor
111-
```
130+
1. Fork 仓库并创建特性分支:`git checkout -b feat/your-feature`
131+
2. 编写代码和测试
132+
3. 运行 `just check` 确保全部通过
133+
4. Push 并在 GitHub 上创建 Pull Request
134+
5. PR 描述中说明改动目的和测试方式
112135

113-
### Python 测试
136+
## 常见问题
114137

115-
```bash
116-
# 运行所有测试
117-
pytest tests/
138+
**Q: `maturin develop` 报错 `linker 'cc' not found`**
139+
140+
Linux 上需要安装 gcc:
118141

119-
# 运行特定测试
120-
pytest tests/actor_system/
142+
```bash
143+
# Ubuntu/Debian
144+
sudo apt install build-essential
145+
# CentOS/Fedora
146+
sudo dnf install gcc gcc-c++
121147
```
122148

123-
## 文档
149+
**Q: 运行测试时报 `ImportError: cannot import name '_core' from 'pulsing'`**
124150

125-
- API 文档使用 rustdoc / docstring
126-
- 设计文档放在 `docs/design/`
127-
- 示例代码放在 `examples/`
151+
需要先编译 Rust 核心:
128152

129-
## 行为准则
153+
```bash
154+
just dev
155+
```
130156

131-
请阅读并遵守我们的 [行为准则](CODE_OF_CONDUCT.md)
157+
**Q: macOS 上 `maturin develop` 很慢**
132158

133-
## 许可证
159+
可以尝试只编译当前架构:
134160

135-
通过贡献代码,你同意你的贡献将在 Apache-2.0 许可证下发布。
161+
```bash
162+
maturin develop --target $(rustc -vV | grep host | cut -d' ' -f2)
163+
```
136164

137-
## 问题?
165+
**Q: 如何只跑某一个测试?**
138166

139-
如果你有任何问题,请通过 [GitHub Issues](https://github.com/DeepLink-org/Pulsing/issues) 联系我们。
167+
```bash
168+
uv run pytest tests/python/test_remote_decorator.py::test_spawn_actor -v
169+
```

README.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,15 +205,37 @@ Pulsing/
205205

206206
## 🛠️ Development
207207

208+
### Prerequisites
209+
210+
- [Rust](https://rustup.rs/) ≥ 1.75
211+
- Python ≥ 3.10
212+
- [uv](https://docs.astral.sh/uv/) (recommended package manager)
213+
- [just](https://github.com/casey/just) (task runner: `cargo install just` or `brew install just`)
214+
215+
### Quick Setup
216+
208217
```bash
209-
# Development build
210-
maturin develop
218+
# 1. Install Python dependencies
219+
uv sync --extra dev
220+
221+
# 2. Compile Rust core and install (run again after any Rust changes)
222+
uv run maturin develop
223+
```
224+
225+
### Common Commands
211226

212-
# Run tests
213-
pytest tests/python/
214-
cargo test --workspace
227+
```bash
228+
just dev # Compile and install in development mode
229+
just test # Run all tests (Rust + Python)
230+
just test-python # Python tests only
231+
just fmt # Format code (Rust + Python)
232+
just lint # Lint check
233+
just check # Full pre-commit check (format + lint + test)
234+
just cov # Generate coverage report
215235
```
216236

237+
See [CONTRIBUTING.md](CONTRIBUTING.md) for a detailed guide on the development workflow.
238+
217239
## 📄 License
218240

219241
Apache-2.0

README.zh.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,15 +205,37 @@ Pulsing/
205205

206206
## 🛠️ 开发
207207

208+
### 前置依赖
209+
210+
- [Rust](https://rustup.rs/) ≥ 1.75
211+
- Python ≥ 3.10
212+
- [uv](https://docs.astral.sh/uv/)(推荐的包管理器)
213+
- [just](https://github.com/casey/just)(任务运行器:`cargo install just``brew install just`
214+
215+
### 快速搭建
216+
208217
```bash
209-
# 开发构建
210-
maturin develop
218+
# 1. 安装 Python 依赖
219+
uv sync --extra dev
220+
221+
# 2. 编译 Rust 核心并安装(修改 Rust 代码后需重新执行)
222+
uv run maturin develop
223+
```
224+
225+
### 常用命令
211226

212-
# 运行测试
213-
pytest tests/python/
214-
cargo test --workspace
227+
```bash
228+
just dev # 编译并安装(开发模式)
229+
just test # 运行全部测试(Rust + Python)
230+
just test-python # 仅运行 Python 测试
231+
just fmt # 格式化代码
232+
just lint # 代码检查
233+
just check # 提交前完整检查(格式 + lint + 测试)
234+
just cov # 生成覆盖率报告
215235
```
216236

237+
详细开发指南请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)
238+
217239
## 📄 License
218240

219241
Apache-2.0

crates/pulsing-actor/src/system/resolve.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::policies::LoadBalancingPolicy;
1212
use crate::system::config::ResolveOptions;
1313
use crate::system::load_balancer::{MemberWorker, NodeLoadTracker};
1414
use crate::system::ActorSystem;
15-
use crate::transport::Http2RemoteTransport;
15+
use crate::transport::{Http2RemoteTransport, TransportTarget};
1616
use std::net::SocketAddr;
1717
use std::sync::Arc;
1818
use std::time::Duration;
@@ -42,8 +42,12 @@ impl ActorSystem {
4242

4343
// Lookup actor location in cluster
4444
if let Some(member_info) = cluster.lookup_actor(id).await {
45-
let transport =
46-
Http2RemoteTransport::new_by_id(self.transport.client(), member_info.addr, *id);
45+
let transport = Http2RemoteTransport::builder(
46+
self.transport.client(),
47+
member_info.addr,
48+
TransportTarget::ById(*id),
49+
)
50+
.build();
4751
return Ok(ActorRef::remote(*id, member_info.addr, Arc::new(transport)));
4852
}
4953

@@ -124,11 +128,12 @@ impl ActorSystem {
124128
if nid != self.node_id {
125129
if let Some(member) = cluster.get_member(&nid).await {
126130
if !options.filter_alive || member.status == MemberStatus::Alive {
127-
let transport = Http2RemoteTransport::new_named(
131+
let transport = Http2RemoteTransport::builder(
128132
self.transport.client(),
129133
member.addr,
130-
path.clone(),
131-
);
134+
TransportTarget::Named(path.clone()),
135+
)
136+
.build();
132137
let actor_id = ActorId::generate();
133138
return Ok(ActorRef::remote(
134139
actor_id,
@@ -188,8 +193,12 @@ impl ActorSystem {
188193
return Ok(ActorRef::local(handle.actor_id, handle.sender.clone()));
189194
}
190195

191-
let transport =
192-
Http2RemoteTransport::new_named(self.transport.client(), target.addr, path.clone());
196+
let transport = Http2RemoteTransport::builder(
197+
self.transport.client(),
198+
target.addr,
199+
TransportTarget::Named(path.clone()),
200+
)
201+
.build();
193202

194203
// For named actors, we don't have a specific ActorId until we resolve
195204
// Use a placeholder ID (this will be replaced when the actor is actually accessed)

0 commit comments

Comments
 (0)