From 08b4c21ca26ce8466f1a71bd873b822faab7f8fe Mon Sep 17 00:00:00 2001 From: wangdl Date: Thu, 18 Jun 2026 14:23:51 +0800 Subject: [PATCH] docs: add V2 event pipeline architecture doc (IOS-INFO-027) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Architecture: iOS export → Rust EventBuffer → API batch upload - Event types, sequence numbers, ACK mechanism - Session state machine, error handling, performance comparison - iOS UploadScheduler integration, app lifecycle handling Co-Authored-By: Claude Opus 4.7 --- docs/v2-event-pipeline.md | 175 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 docs/v2-event-pipeline.md diff --git a/docs/v2-event-pipeline.md b/docs/v2-event-pipeline.md new file mode 100644 index 0000000..5441fbd --- /dev/null +++ b/docs/v2-event-pipeline.md @@ -0,0 +1,175 @@ +# V2 事件 Pipeline 架构 + +## 1. 概述 + +V2 事件 Pipeline 是 Document Runtime(Rust FFI)+ iOS Swift 层协作的阅读行为采集链路。 + +与 V1 的区别: +- V1:每个事件独立 push,iOS 手动管理 buffer +- V2:Rust 层内置 EventBuffer + 序列号 + ACK 机制,iOS 仅负责定时 export + +--- + +## 2. 架构 + +``` +┌──────────────────────────────────────────────────┐ +│ iOS Swift │ +│ UploadScheduler (30s timer) │ +│ → documentRuntime.exportPending() │ +│ → POST /api/reading-events/batch │ +│ → documentRuntime.ackExported(count) │ +└──────────────────┬───────────────────────────────┘ + │ FFI (uniffi) +┌──────────────────▼───────────────────────────────┐ +│ Rust: zx_document_core │ +│ │ +│ ┌─ push_opened() │ +│ ├─ push_heartbeat_v2(position?) │ +│ ├─ push_position_changed() │ +│ ├─ push_closed() │ +│ ├─ push_marked_as_read() │ +│ └─ mark_events_failed_v2(ids) │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────┐ │ +│ │ EventBuffer (Mutex) │ │ +│ │ - max 1000 events │ │ +│ │ - auto-increment seq │ │ +│ │ - session state tracking │ │ +│ └──────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ export_pending() → Vec │ +│ clear_exported(count) │ +│ mark_events_failed_v2(ids) │ +└──────────────────────────────────────────────────┘ +``` + +--- + +## 3. 事件类型 + +| 事件 | 触发时机 | 携带数据 | +|------|----------|----------| +| `opened` | `openMaterial()` | materialId | +| `heartbeat` | 定时器 (30s) | position? | +| `position_changed` | 滚动/翻页 | position | +| `closed` | `closeMaterial()` | totalActiveMs | +| `marked_as_read` | `markAsRead()` | — | +| `failed` | 异常/超时 | errorCode | + +--- + +## 4. 序列号与 ACK + +``` +每个事件分配递增序列号(session 内自增) +iOS export 获得 Vec<(seq, event)> +上传 API 成功 → ACK exported count → Rust 移除已确认事件 +上传失败 → mark_events_failed_v2(ids) → 事件保留,下次重试 +``` + +### 4.1 export → ACK 流程 + +``` +1. iOS 调用 exportPending() → Vec +2. iOS 将 events 序列化为 JSON,POST /api/reading-events/batch +3. 成功 → clearExported(count) → Rust 移除前 count 条 +4. 失败 → 事件保留在 buffer,下次 export 仍包含 +``` + +### 4.2 会话恢复 + +``` +App 重启 → SessionManager.reload_stale_events() + → 将上次未 ack 的事件标记为 failed + → 返回可重试的事件列表 +``` + +--- + +## 5. iOS 集成 + +### 5.1 UploadScheduler + +```swift +class UploadScheduler { + let interval: TimeInterval = 30 + + func start() { + Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in + Task { await self.flush() } + } + } + + func flush() async { + let events = documentRuntime.exportPending() + guard !events.isEmpty else { return } + do { + try await api.uploadEvents(events) + documentRuntime.clearExported(events.count) + } catch { + // Events remain in buffer for retry + } + } +} +``` + +### 5.2 App 生命周期 + +```swift +// sceneDidEnterBackground +UploadScheduler.shared.flush() // 强制上传 + +// App 启动 +RuntimeRecoveryService.shared.recover() // 恢复未完成会话 +``` + +--- + +## 6. Session 状态机 + +``` + openMaterial() + ┌─ idle ─────────────────► opened + │ │ + │ heartbeat/ + │ position_change + │ │ + │ ▼ + │ reading + │ │ + │ closeMaterial() + │ │ + └──────── closed ◄───────────┘ +``` + +--- + +## 7. 错误处理 + +| 场景 | 处理 | +|------|------| +| Buffer 满(1000条) | 拒绝新事件,iOS 应触发 flush | +| FFI 调用失败 | fallback 到 V1 NoopReadingRuntimeAdapter | +| 网络不可用 | 事件保留,下次 export 包含未 ACK 事件 | +| Session 超时(无活动 30min) | cleanup_stale_sessions_v2 自动清理 | + +--- + +## 8. 性能特征 + +| 指标 | V1 | V2 | +|------|:--:|:--:| +| FFI 调用频率 | 每事件 1 次 | 每批次 1 次 | +| 内存占用 | ~50 events × iOS heap | ~1000 events × Rust heap | +| 序列号 | 无 | Session 内自增 | +| ACK 粒度 | 无 | Batch 级别 | + +--- + +## 9. 相关文档 + +- [阅读信息采集接入文档](./reading-info-integration.md) +- [Rust FFI 绑定更新流程](./rust-ffi-update.md)