跳到主要内容

事件总线

VEF 会自动启动一个内存事件总线,并通过公共 event 包对外暴露。

模块自动提供的内容

事件模块会注册一个内存总线,并以这些接口形式暴露:

接口
event.Bus
event.Publisher
event.Subscriber

这个总线会通过 FX 生命周期自动启动和停止。

核心事件接口

event.Event

自定义事件应实现以下方法:

方法含义
ID()唯一事件实例 ID
Type()事件类型字符串
Source()事件来源
Time()发生时间
Meta()元数据 map

发布与订阅接口

接口方法
event.PublisherPublish(event)
event.SubscriberSubscribe(eventType, handler)
event.Bus组合了 PublisherSubscriberStart()Shutdown(ctx)

中间件接口

接口或类型作用
event.Middleware拦截事件投递
event.MiddlewareFunc中间件链的下一跳函数

event.BaseEvent

绝大多数自定义事件都会嵌入 event.BaseEvent

type UserCreatedEvent struct {
event.BaseEvent

UserID string `json:"userId"`
}

创建 base 部分的方式:

&UserCreatedEvent{
BaseEvent: event.NewBaseEvent(
"user.created",
event.WithSource("user-service"),
event.WithMeta("scope", "admin"),
),
UserID: "user-1001",
}

BaseEvent 相关 helper:

Helper含义
event.NewBaseEvent(type, opts...)创建基础事件
event.WithSource(source)设置 source
event.WithMeta(key, value)添加 metadata

发布与订阅示例

package userevents

import (
"context"

"github.com/coldsmirk/vef-framework-go/event"
)

func PublishUserCreated(publisher event.Publisher, userID string) {
publisher.Publish(&UserCreatedEvent{
BaseEvent: event.NewBaseEvent("user.created"),
UserID: userID,
})
}

func RegisterUserCreatedHandler(subscriber event.Subscriber) event.UnsubscribeFunc {
return subscriber.Subscribe("user.created", func(ctx context.Context, evt event.Event) {
_ = evt
})
}

事件中间件

事件总线支持通过 FX group 挂载事件中间件:

vef:event:middlewares

适合放在这里的横切能力包括:

  • 事件日志
  • tracing
  • 过滤
  • 事件投递前的轻量变换

框架内置事件类型

框架当前会发布以下核心事件类型:

事件类型来源
vef.api.request.auditAPI 审计事件
vef.security.login登录流程事件
vef.storage.file.promotedstorage promoter 事件
vef.storage.file.deletedstorage promoter 事件
vef.security.role_permissions.changed角色权限缓存失效事件

如果启用了 approval 模块,它还会额外发布一批审批领域事件,但那一层属于业务域事件,而不是这里的框架核心事件。

常见接线模式

在规模稍大的应用里,订阅者通常不是在资源里注册,而是放在一个集成模块里:

var Module = vef.Module(
"app:event",
vef.Invoke(registerEventSubscribers),
)

这个 registerEventSubscribers 函数可以订阅框架事件,并在需要时自行挂生命周期清理逻辑。

什么时候使用它

内置事件总线适合以下场景:

  • 生产者和消费者都在同一个应用进程内
  • 只需要异步解耦,不需要外部消息代理
  • 当前还不需要跨进程消息系统

即使未来需要跨进程消息系统,也仍然可以保留这个内置总线作为应用层抽象。

下一步

继续阅读 缓存,如果你想把事件发布和缓存失效、异步刷新流程串起来,它会直接用到。