mocra 0.3.0

A distributed, event-driven crawling and data collection framework
# 设计文档

本文解释 `mocra` 面向使用者的核心概念。

## 模块设计

一个爬虫以 `ModuleTrait` 实现的形式封装。

必须实现的方法:

```rust
fn name(&self) -> &'static str;
fn version(&self) -> i32;
fn default_arc() -> Arc<dyn ModuleTrait>
where
    Self: Sized;
```

常用可选方法:

- `rate_limit()` 设置模块请求速率;
- `proxy_pool()` 选择代理池;
- `timeout_secs()` 覆盖请求超时时间;
- `priority()` 设置请求优先级;
- `serial_execution()` 请求模块串行执行;
- `module_locker()` 启用模块级锁;
- `enable_session()` 启用会话;
- `response_cache_enabled()` 启用响应缓存;
- `response_cache_ttl_secs()` 覆盖响应缓存 TTL;
- `cron()` 启用定时调度;
- `pre_process()``post_process()` 添加模块生命周期钩子。

## 节点设计

每个节点实现 `ModuleNodeTrait`:

```rust
async fn generate(&self, ctx: NodeGenerateContext<'_>) -> Result<SyncBoxStream<'static, Request>>;

async fn parser(&self, response: Response, ctx: NodeParseContext<'_>) -> Result<NodeParseOutput>;
```

节点应尽量保持执行期间不可变。分页游标、业务 ID、路由信息等可变进度状态应放在请求 metadata、节点输入或 profile/config 数据中。

生产 DAG 节点应覆盖 `stable_node_key()`。稳定 key 可以保证模块重建后,重试和 parser dispatch 仍能路由到正确节点。

## 线性工作流

简单工作流可以实现 `add_step()`:

```rust
async fn add_step(&self) -> Vec<Arc<dyn ModuleNodeTrait>> {
    vec![Arc::new(ListNode), Arc::new(DetailNode)]
}
```

运行时会根据返回的节点列表构建线性 DAG。

## 显式 DAG

分支、汇聚或非线性流程应实现 `dag_definition()`。它返回包含节点和边的 `ModuleDagDefinition`。

以下场景适合使用显式 DAG:

- 一个响应会路由到不同类型的节点;
- 节点有多个下游目标;
- 工作流存在 join 或非线性执行;
- 需要控制节点 placement 或执行策略。

`NodePlacement::Local` 表示本地执行。`NodePlacement::Remote { worker_group }` 是高级路由提示,需要运行时部署提供 dispatcher 支持。

## 解析输出

`NodeParseOutput` 是 parser 的输出契约:

```rust
NodeParseOutput::default()
    .with_next(NodeDispatch::new("detail", input))
    .with_data(parsed)
    .finish()
```

使用 `with_next(...)` 继续工作流,使用 `with_data(...)` 输出解析数据,使用 `finish()` 标记完成。

## Request 和 Response

创建请求:

```rust
Request::new("https://example.com", "GET")
```

常用 request builder:

- `with_params(...)`
- `with_headers(...)`
- `with_cookies(...)`
- `with_json(...)`
- `with_body(...)`
- `with_form(...)`
- `add_meta(...)`
- `with_sleep(...)`
- `enable_session(...)`
- `enable_response_cache(...)`

`Response` 携带下载后的响应体、执行上下文和 parser 所需 metadata。

## 中间件

运行时支持 download、data 和 store 三类中间件。在 `start()` 前注册:

```rust
engine.register_download_middleware(middleware).await;
engine.register_data_middleware(middleware).await;
engine.register_store_middleware(middleware).await;
```

中间件适合实现请求改写、响应规范化、数据转换和存储处理等横切逻辑。

## 当前边界

当前代码库不提供 Redis 兼容能力。不要为缓存、队列、锁、同步、事件或限流配置 Redis。

旧分布式爬虫路径的回滚兼容不是面向使用者的能力。新应用应使用当前 typed DAG、队列、缓存和 Raft/RocksDB 路径。