♻️ refactor(outbox): 抽离通用事件总线,并完成 event_type-only 收口 - ✨ 新增 `infra` 层通用 `EventBus` / `EventContract`,统一事件发布与消费协议 - 🔄 将聊天持久化链路调整为通过 `service/events` 注册 handler 并发布事件,进一步解耦业务逻辑与异步处理流程 - 🧹 移除 `chat_history_async` 旧适配实现,以及基于 `biz_type` 的兼容分发逻辑 - 📝 更新 Outbox 异步持久化决策记录,明确保留方案 A,并正式启用方案 B - 📚 同步更新 README 中关于 Outbox + Kafka 可靠异步链路的说明 - 🚚 当前 `outbox + kafka` 已与项目业务链路完全解耦,沉淀为通用、可靠性更强的消息队列能力;后续将参考消息队列的典型使用方式,逐步扩展到更多业务场景 - ✨ 补充跨不同分类事务管理器中的 `agent dao` 注册与接入支持
88 lines
2.7 KiB
Go
88 lines
2.7 KiB
Go
package outbox
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
|
||
kafkabus "github.com/LoveLosita/smartflow/backend/infra/kafka"
|
||
)
|
||
|
||
// EventPublisher 是通用事件发布能力接口。
|
||
//
|
||
// 职责边界:
|
||
// 1. 只暴露“发布事件”这一件事,隐藏底层 outbox/kafka 实现细节;
|
||
// 2. 业务层只依赖该接口,避免直接耦合具体引擎结构体;
|
||
// 3. 该接口不承诺“立即消费成功”,只承诺“事件已入队或返回错误”。
|
||
type EventPublisher interface {
|
||
Publish(ctx context.Context, req PublishRequest) error
|
||
}
|
||
|
||
// EventBus 是 outbox 异步总线的门面对象。
|
||
//
|
||
// 设计目的:
|
||
// 1. 对外提供“发布 + 注册处理器 + 启停”三类最小能力;
|
||
// 2. 对内复用 Engine,不重复实现状态机和调度逻辑;
|
||
// 3. 为后续引入更多事件类型提供统一扩展点。
|
||
type EventBus struct {
|
||
engine *Engine
|
||
}
|
||
|
||
// NewEventBus 创建通用事件总线。
|
||
//
|
||
// 说明:
|
||
// 1. 当 kafka.enabled=false 时返回 nil,调用方可直接降级为同步模式;
|
||
// 2. 该方法只创建基础设施对象,不自动注册任何业务事件处理器;
|
||
// 3. 业务事件处理器注册应由上层在启动阶段显式完成,避免隐式副作用。
|
||
func NewEventBus(repo *Repository, cfg kafkabus.Config) (*EventBus, error) {
|
||
engine, err := NewEngine(repo, cfg)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if engine == nil {
|
||
return nil, nil
|
||
}
|
||
return &EventBus{engine: engine}, nil
|
||
}
|
||
|
||
// RegisterEventHandler 注册事件处理器。
|
||
//
|
||
// 失败语义:
|
||
// 1. bus 未初始化时直接返回错误;
|
||
// 2. event_type 为空或 handler 为空时返回错误;
|
||
// 3. 重复注册时采用“后者覆盖前者”并打日志(由 Engine 负责)。
|
||
func (b *EventBus) RegisterEventHandler(eventType string, handler MessageHandler) error {
|
||
if b == nil || b.engine == nil {
|
||
return errors.New("event bus is not initialized")
|
||
}
|
||
return b.engine.RegisterEventHandler(eventType, handler)
|
||
}
|
||
|
||
// Publish 发布事件到 outbox 队列。
|
||
//
|
||
// 关键语义:
|
||
// 1. 返回 nil 仅表示“已写入 outbox 成功”;
|
||
// 2. 真正 Kafka 投递与业务消费由后台异步循环完成;
|
||
// 3. 若返回 error,表示本次入队失败,调用方应按业务策略决定是否重试/降级。
|
||
func (b *EventBus) Publish(ctx context.Context, req PublishRequest) error {
|
||
if b == nil || b.engine == nil {
|
||
return errors.New("event bus is not initialized")
|
||
}
|
||
return b.engine.Publish(ctx, req)
|
||
}
|
||
|
||
// Start 启动事件总线后台循环(dispatch + consume)。
|
||
func (b *EventBus) Start(ctx context.Context) {
|
||
if b == nil || b.engine == nil {
|
||
return
|
||
}
|
||
b.engine.Start(ctx)
|
||
}
|
||
|
||
// Close 关闭事件总线资源(producer/consumer)。
|
||
func (b *EventBus) Close() {
|
||
if b == nil || b.engine == nil {
|
||
return
|
||
}
|
||
b.engine.Close()
|
||
}
|