api-server/docs/architecture/adr-001-appendix-a-worker-dependency-closure.md
wangdl 54bc505f7a docs: add ADR-001 unified AI architecture decision record
Freeze the architecture decision for 8-batch unified AI migration.
Covers current/target topology, API/Worker process boundaries,
5 Processors, Heavy Runtime disposition, phase-1 non-goals,
rollback principles, and cross-batch constraints.

Includes Appendix A: worker dependency closure audit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 20:10:35 +08:00

9.0 KiB
Raw Blame History

ADR-001 附录 AWorker 执行依赖闭包审计

审计日期

2026-06-19

目标

确认每个 BullMQ Processor 的完整依赖、事件和副作用,防止 Processor 移到独立 Worker 进程后链路断裂。


一、Processor 依赖矩阵

1.1 AiAnalysisWorker

维度 事实 证据
队列 ai-analysis @Processor(QUEUE_AI_ANALYSIS)
注册位置 AppModule (line 193) + WorkerModule (line 62) — 双重注册 app.module.ts:193worker.module.ts:62
注入依赖 ActiveRecallAnalysisWorkflowFeynmanEvaluationWorkflowAiAnalysisRepositoryEventBusService (@Optional)、FocusItemsService (@Optional) ai-analysis.worker.ts:22-28
依赖 Module AiModule(提供 WorkflowAiAnalysisModule(提供 RepositoryEventBusModule(提供 EventBusServiceFocusItemsModule(提供 FocusItemsService
写入的表 AiAnalysisJobupdateJobStatusAiAnalysisResultcreateResultFocusItemcreate ai-analysis.worker.ts:47,66,67,87,101
发布的事件 ai.analysis.completed(通过 EventBusService.publish()EventEmitter2.emit()进程内 ai-analysis.worker.ts:71
事件订阅者 ReviewCardSubscriber@OnEvent('ai.analysis.completed')ReviewModuleAppModule review-card.subscriber.ts:11
WorkerModule 中缺失 FocusItemsModule 未导入 → FocusItemsService 在 Worker 进程中为 null worker.module.ts:1-66
移动后断裂链路 ⚠️ ai.analysis.completed 事件无法到达 ReviewCardSubscriber(进程内 EventEmitter2⚠️ FocusItemsService 在独立 Worker 进程中为 null

1.2 DocumentImportWorker

维度 事实 证据
队列 document-import @Processor(QUEUE_DOCUMENT_IMPORT)
注册位置 AppModule (line 194) + WorkerModule (line 65) — 双重注册 app.module.ts:194worker.module.ts:65
注入依赖 KnowledgeImportWorkflowKnowledgeItemsRepositoryRedisService 需确认 document-import.worker.ts
写入的表 KnowledgeItem
发布的事件
移动后断裂链路 无事件依赖,但需确认 Redis 连接在 Worker 进程中可用

1.3 NotificationWorker

维度 事实 证据
队列 notification @Processor(QUEUE_NOTIFICATION)
注册位置 AppModule (line 195) + WorkerModule (line 66) — 双重注册 app.module.ts:195worker.module.ts:66
注入依赖 NotificationsService 需确认 notification.worker.ts
写入的表 Notification(更新发送状态)
发布的事件
移动后断裂链路 需确认 NotificationsService 及其 Module 依赖在 WorkerModule 中可用

1.4 AuditLogProcessor

维度 事实 证据
队列 audit-logs @Processor(QUEUE_AUDIT_LOG)
注册位置 AdminAuditLogModule providers仅注册一次未双重 admin-audit-log.module.ts:13
注入依赖 PrismaService audit-log.processor.ts:7
写入的表 AdminAuditLog audit-log.processor.ts:12-23
发布的事件
移动后断裂链路 无业务事件依赖,但 AdminAuditLogModule 同时包含 Controller 和 Processor需要拆分

1.5 FileCleanupProcessor

维度 事实 证据
队列 file-cleanup @Processor(QUEUE_FILE_CLEANUP)
注册位置 ⚠️ FilesModule 导入了 FileCleanupProcessor未在 providers 中注册BullExplorer 扫描可能仍能发现,但依赖注入不可靠 files.module.ts:3,12-14
注入依赖 CosStorageProvider file-cleanup.processor.ts:10
写入的表 无(直接操作 COS
发布的事件
移动后断裂链路 需确认 CosStorageProvider 在 Worker 进程中可注入

二、事件链路审计

2.1 EventBusService 实现

方法 机制 跨进程 证据
publish(event) EventEmitter2.emit() — 进程内同步 event-bus.service.ts:19-22
publishAsync(event) BullMQ domain-events 队列 — 跨进程异步 event-bus.service.ts:26-36

2.2 当前事件使用

事件 发布者 发布方式 订阅者 订阅方式 位置 跨进程安全
ai.analysis.completed AiAnalysisWorker publish()(进程内) ReviewCardSubscriber @OnEventEventEmitter2 review-card.subscriber.ts:11
task.enqueued QueueService publish()(进程内) 无消费者 queue.service.ts:34
streak.updated GrowthService publish()(进程内) 无消费者 growth.service.ts:53

2.3 Domain Events 队列

  • 生产者EventBusService.publishAsync()queue.add('domain-events', ...)
  • 消费者:无 — 代码库中无任何 @Processor('domain-events')
  • 状态:死队列 — 事件被写入 Redis 但永不被处理
  • 结论publishAsync() 当前无实际效果

2.4 移动后的断裂链路

移动前(同进程):
  AiAnalysisWorker → EventBusService.publish() → EventEmitter2.emit('ai.analysis.completed')
    → ReviewCardSubscriber.@OnEvent('ai.analysis.completed')
    → reviewService.generateCards() → ReviewCard 创建 ✅

移动后(跨进程):
  Worker 进程: AiAnalysisWorker → EventBusService.publish() → EventEmitter2.emit()
  API 进程: ReviewCardSubscriber.@OnEvent() — 收不到 ❌

影响AI 分析完成后不再自动生成复习卡片。


三、Module 注册审计

3.1 双重注册的 Processor

Processor AppModule WorkerModule 业务 Module 问题
AiAnalysisWorker (line 193) (line 62) 若两个 Module 均加载BullMQ 创建两个 Worker 实例消费同一队列 → 并发双消费
DocumentImportWorker (line 194) (line 65) 同上
NotificationWorker (line 195) (line 66) 同上

3.2 需拆分的 Module同时包含 Controller 和 Processor

Module Controller Processor Producer
AdminAuditLogModule (AuditLogProcessor)
FilesModule ⚠️ (FileCleanupProcessor 导入但未在 providers 注册) (FilesService)

四、WorkerModule 缺失依赖

当前 WorkerModuleworker.module.ts:1-66)导入的 Module

PrismaModule, RedisModule, QueueModule, AiModule, StorageModule,
LoggerModule, AiAnalysisModule, DocumentImportModule, KnowledgeItemsModule, NotificationsModule

缺失但 AiAnalysisWorker 需要的 Module

缺失 Module 提供的 Service 影响
FocusItemsModule FocusItemsService AiAnalysisWorker 中 focusItems 为 null不创建 FocusItem
EventBusModule EventBusService AiAnalysisWorker 中 eventBus 为 null不发布事件。但当前有 @Optional() 标记,不会崩溃
ReviewModule ReviewCardSubscriber 即使事件发布成功(使用 publishAsync无订阅者处理

五、修复建议矩阵(供 01-03 使用)

问题 修复方向 优先级
AiAnalysisWorker/NotificationWorker/DocumentImportWorker 双重注册 AppModule providers 中移除,仅保留在 WorkerModule 阻塞
EventBusService.publish() 无法跨进程 选项 AReviewCardSubscriber 移入 WorkerModule;选项 B改为 publishAsync() + 新增 DomainEventsProcessor 消费 domain-events 队列 阻塞
FocusItemsModule 未在 WorkerModule 添加 FocusItemsModuleWorkerModule.imports 阻塞
ReviewModule 未在 WorkerModule 如果选 A需在 WorkerModule 中导入 ReviewModule(或拆出 ReviewWorkerModule 阻塞
AuditLogProcessorAdminAuditLogModule 拆分为 AdminAuditLogProducerModule + AdminAuditLogWorkerModule,或将其移入 WorkerModule 并保留 Controller 在原 Module
FileCleanupProcessor 未在 providers 中注册 补充注册,或显式移入 WorkerModule

六、无法确认项

项目 状态 原因
Docker Compose 当前是否同时启动 API 和 Worker 无法确认 需检查 docker-compose.ymlcommandentrypoint 指向 dist/main.js 还是两者
生产 systemd 是否使用独立 Worker 进程 无法确认 无法访问生产服务器
NotificationsService 的完整依赖链 未深入审计 NotificationWorker 的审计超出了当前 Issue 范围,需后续补充