250702-filewatcher-progress-fix.md•5.76 kB
# FileWatcher 进度报告修复经验总结
**日期**: 2025-07-02
**问题**: 文件监控时没有进度提示,或进度显示不合理
**解决方案**: 将 FileWatcher 进度报告从文件级别改为代码块级别
## 问题分析
### 原始问题
用户反馈:初始索引时有详细的进度提示("Indexed X / Y blocks found"),但文件监控时没有任何进度显示。
### 深入调查发现的根本问题
1. **进度语义不一致**
- 初始扫描:使用 `reportBlockIndexingProgress()` - 按代码块显示
- 文件监控:使用 `reportFileQueueProgress()` - 按文件显示
2. **BatchProcessor 与 FileWatcher 进度语义冲突**
```typescript
// BatchProcessor 报告代码块级别的进度
onProgress: (processed, total) => {
// processed/total 是代码块数量
}
// 但 FileWatcher 期望文件级别的进度
this.eventBus.emit('batch-progress', {
processedInBatch: processed, // 实际是代码块数,不是文件数
totalInBatch: total, // 实际是代码块总数,不是文件总数
})
```
3. **用户体验问题**
- 大文件有很多代码块,按文件显示进度会让用户感觉卡住
- 进度更新频率低,用户体验差
## 解决方案设计
### 选择的方案:代码块级别进度
**理由**:
- 与初始扫描保持一致
- 大文件不会让用户感觉卡住
- 进度更新更频繁,用户体验更好
### 技术实现策略
1. **保持向后兼容**:新增 `batch-progress-blocks` 事件,保留原有 `batch-progress` 事件
2. **统一进度语义**:文件监控和初始扫描都使用 `reportBlockIndexingProgress()`
3. **合理的块计算**:删除的文件按 1 文件 = 1 块计算
## 具体修改
### 1. FileWatcher 代码修改
#### 添加代码块级别计数器
```typescript
// 替换文件级别计数器
let totalBlocksInBatch = 0
let processedBlocksInBatch = 0
// 计算总块数(包括删除的文件)
totalBlocksInBatch = blocksToUpsert.length + filesToDelete.length
```
#### 新增代码块级别事件
```typescript
// 初始进度
this.eventBus.emit('batch-progress-blocks', {
processedBlocks: 0,
totalBlocks: totalBlocksInBatch,
})
// 处理过程中的进度
this.eventBus.emit('batch-progress-blocks', {
processedBlocks: processedBlocksInBatch,
totalBlocks: totalBlocksInBatch,
})
```
#### 优化 BatchProcessor 集成
```typescript
// 使用 BatchProcessor 的进度回调
onProgress: (processed, total) => {
this.eventBus.emit('batch-progress-blocks', {
processedBlocks: processedBlocksInBatch + processed,
totalBlocks: totalBlocksInBatch,
})
},
```
### 2. 接口扩展
```typescript
// file-processor.ts 和 file-watcher.ts
readonly onBatchProgressBlocksUpdate: (handler: (data: {
processedBlocks: number
totalBlocks: number
}) => void) => () => void
```
### 3. Orchestrator 调整
```typescript
// 从文件级别改为代码块级别
this.fileWatcher.onBatchProgressBlocksUpdate(({ processedBlocks, totalBlocks }) => {
this.stateManager.reportBlockIndexingProgress(
processedBlocks,
totalBlocks,
)
})
```
## 关键技术要点
### 1. 事件命名策略
- `batch-progress`: 文件级别(向后兼容)
- `batch-progress-blocks`: 代码块级别(新增)
### 2. 进度计算逻辑
```typescript
// 删除操作:每个文件计为 1 块
for (const filePath of filesToDelete) {
processedBlocksInBatch++
this.eventBus.emit('batch-progress-blocks', {
processedBlocks: processedBlocksInBatch,
totalBlocks: totalBlocksInBatch,
})
}
// 代码块处理:使用 BatchProcessor 的实际进度
onProgress: (processed, total) => {
this.eventBus.emit('batch-progress-blocks', {
processedBlocks: processedBlocksInBatch + processed,
totalBlocks: totalBlocksInBatch,
})
}
```
### 3. StateManager 集成
- 文件监控使用 `reportBlockIndexingProgress()` 而不是 `reportFileQueueProgress()`
- 显示格式:`"Indexed X / Y blocks found"`
## 测试验证
### 构建验证
```bash
npm run build # 成功构建,无新的类型错误
```
### 预期效果
- ✅ 文件监控显示:`"Indexed X / Y blocks found"`
- ✅ 与初始扫描进度格式一致
- ✅ 大文件处理时显示流畅的进度更新
- ✅ 向后兼容,不影响现有功能
## 经验教训
### 1. 问题诊断方法
1. **跟踪数据流**:从事件发射到最终显示的完整路径
2. **对比分析**:初始扫描 vs 文件监控的差异
3. **语义分析**:确保进度数据的语义一致性
### 2. 架构设计原则
1. **向后兼容**:新增功能不破坏现有接口
2. **语义一致**:相同类型的操作使用相同的进度报告方式
3. **用户体验优先**:选择对用户更友好的进度显示方式
### 3. 代码修改策略
1. **接口优先**:先定义清晰的接口,再实现具体逻辑
2. **渐进式修改**:逐步替换,保持每一步都可验证
3. **测试驱动**:每次修改后立即构建验证
## 相关文件
### 主要修改文件
- `src/code-index/processors/file-watcher.ts` - 核心逻辑修改
- `src/code-index/interfaces/file-processor.ts` - 接口扩展
- `src/code-index/orchestrator.ts` - 事件订阅调整
### 相关组件
- `src/code-index/state-manager.ts` - 进度状态管理
- `src/code-index/processors/batch-processor.ts` - 批处理器
- `src/code-index/processors/scanner.ts` - 初始扫描器(参考实现)
## 后续优化建议
1. **性能优化**:考虑批量发送进度事件,避免过于频繁的更新
2. **错误处理**:增强错误状态下的进度报告
3. **用户配置**:允许用户选择进度显示粒度(文件级 vs 代码块级)
4. **监控指标**:添加进度报告的性能监控