♻️ 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` 注册与接入支持
65 lines
1.8 KiB
Go
65 lines
1.8 KiB
Go
package outbox
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// DefaultEventVersion 是通用事件协议默认版本。
|
|
DefaultEventVersion = "v1"
|
|
)
|
|
|
|
// OutboxEventPayload 是 outbox.payload 的统一事件外壳。
|
|
type OutboxEventPayload struct {
|
|
EventID string `json:"event_id,omitempty"`
|
|
EventType string `json:"event_type"`
|
|
EventVersion string `json:"event_version,omitempty"`
|
|
AggregateID string `json:"aggregate_id,omitempty"`
|
|
Payload json.RawMessage `json:"payload"`
|
|
}
|
|
|
|
// ParsedOutboxEventPayload 是 dispatch 阶段使用的标准化结构。
|
|
type ParsedOutboxEventPayload struct {
|
|
EventID string
|
|
EventType string
|
|
EventVersion string
|
|
AggregateID string
|
|
PayloadJSON json.RawMessage
|
|
}
|
|
|
|
// parseOutboxEventPayload 解析 outbox.payload。
|
|
//
|
|
// 当前策略(极致清理版):
|
|
// 1. 只接受“统一事件外壳”格式;
|
|
// 2. 不再支持旧格式纯业务 JSON 回退;
|
|
// 3. event_type 缺失时直接报错,交由上层标 dead。
|
|
func parseOutboxEventPayload(rawPayload string) (*ParsedOutboxEventPayload, error) {
|
|
var wrapped OutboxEventPayload
|
|
if err := json.Unmarshal([]byte(rawPayload), &wrapped); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
eventType := strings.TrimSpace(wrapped.EventType)
|
|
if eventType == "" {
|
|
return nil, errors.New("event type is empty")
|
|
}
|
|
if len(wrapped.Payload) == 0 {
|
|
return nil, errors.New("payload is empty")
|
|
}
|
|
|
|
eventVersion := strings.TrimSpace(wrapped.EventVersion)
|
|
if eventVersion == "" {
|
|
eventVersion = DefaultEventVersion
|
|
}
|
|
|
|
return &ParsedOutboxEventPayload{
|
|
EventID: strings.TrimSpace(wrapped.EventID),
|
|
EventType: eventType,
|
|
EventVersion: eventVersion,
|
|
AggregateID: strings.TrimSpace(wrapped.AggregateID),
|
|
PayloadJSON: wrapped.Payload,
|
|
}, nil
|
|
}
|