activity-events
SKILL.md
活动事件系统开发指南
帮助你使用活动框架的事件系统实现异步消息处理、业务解耦和延迟任务。
🤖 AI 执行指令
当用户调用此 skill 时,根据需求提供事件系统的使用指导和代码示例。
使用场景判断
- 监听业务事件 → 提供 Handler 注册和编写模板
- 发布事件 → 提供 PublishStruct / PublishCustomizedTopic 示例
- 创建延迟任务 → 提供延迟任务注册和创建方法
- 添加新事件 → 提供完整的新增 Topic 步骤
设计原理
采用 发布-订阅模式,基于 Redis List 实现异步消息队列:
发布者 → LPUSH act_chan:topic:{topic} → 消费协程 BRPOP → 并发分发给 Handlers
并发控制:信号量限制最大 500 并发,每个 handler 独立 panic 恢复。
事件分类(300+ Topic)
| 分类 | 典型事件 |
|---|---|
| 充值/支付 | charge, refund, first_charge, direct_purchase |
| 礼物 | send_gift, buy_gift_package |
| 成长/属性 | add_growth, add_charm, add_points |
| 语音房 | voice_room, enter_exit_vr_room |
| 家族 | family_active, donate_family_coin |
| 社交 | add_friend, marry_propose |
| 账户 | login, register |
| 自定义 | customized:{actId}:{topic} |
发布事件
// 标准发布 - 将结构体序列化后推入 Redis List
actevent.PublishStruct("send_gift", eventData)
// 自定义活动事件 - 仅当前活动消费
actevent.PublishCustomizedTopic(actId, "my_topic", data)
消费事件
// 标准注册 - 一个 topic 可挂载多个 handler
actevent.Register(actevent.TopicSendGift,
handler1, handler2, handler3,
)
在活动的 GetEvents() 方法中声明事件绑定:
func (a *MyActivity) GetEvents() []actmodel.Event {
return []actmodel.Event{
{Topic: actevent.TopicSendGift, Handler: myHandler},
{Topic: actevent.TopicCharge, Handler: chargeHandler},
}
}
Handler 标准写法
func HandleXXX(data string) {
entry := logrus.WithField("data", data)
entry.Infoln("component HandleXXX start")
// 1. 反序列化
eventData := &actevent.SomeEvent{}
if err := json.Unmarshal([]byte(data), eventData); err != nil {
entry.WithField("err", err).Errorln("Unmarshal err")
return
}
// 2. 校验关键字段
if eventData.Uid <= 0 { return }
// 3. 执行业务逻辑
service.ProcessEvent(eventData)
}
Handler 编写要点
- 入口日志:必须打印
start日志,方便追踪 - 反序列化:使用
json.Unmarshal,失败时记录 error 并 return - 字段校验:关键字段(uid、actId)为零值时直接 return
- 业务逻辑:调用 service 层处理,保持 handler 精简
- panic 安全:框架已做 panic 恢复,但仍建议做好错误处理
延迟任务
基于 Redis Sorted Set(score = 执行时间戳),轮询 ZPopMin 消费:
注册延迟任务
// 在 GetDeferTasks() 中声明
func (a *MyActivity) GetDeferTasks() []actmodel.DeferTask {
return []actmodel.DeferTask{
{ActId: conf.ActId, TaskType: "send_reward", Handler: handleSendReward},
}
}
// 或直接注册
RegisterDeferTask(actId, "task_type", handler)
创建延迟任务实例
// 在未来某个时间执行
actutil.CreateDeferTask(key, data, executeAt)
添加新事件的完整步骤
1. 定义 Topic 常量和数据结构
文件:actevent/topic.go
const TopicMyNewEvent = "my_new_event"
type MyNewEventData struct {
Uid int `json:"uid"`
ActId int `json:"act_id"`
Amount int `json:"amount"`
}
2. 编写 Handler
文件:组件的 event.go
func HandleMyNewEvent(data string) {
entry := logrus.WithField("data", data)
entry.Infoln("HandleMyNewEvent start")
eventData := &actevent.MyNewEventData{}
if err := json.Unmarshal([]byte(data), eventData); err != nil {
entry.WithField("err", err).Errorln("Unmarshal err")
return
}
if eventData.Uid <= 0 { return }
// 业务逻辑
}
3. 注册 Handler
文件:register.go 的 GetEvents() 方法
{Topic: actevent.TopicMyNewEvent, Handler: HandleMyNewEvent},
4. 在触发位置发布事件
actevent.PublishStruct(actevent.TopicMyNewEvent, &actevent.MyNewEventData{
Uid: uid,
ActId: actId,
Amount: amount,
})
自定义活动事件
当标准 Topic 不满足需求时,使用自定义事件(仅在当前活动内消费):
// 发布
actevent.PublishCustomizedTopic(actId, "my_custom_topic", data)
// 消费 - Topic 格式为 customized:{actId}:{topic}
典型使用场景
场景 1:监听送礼事件
/activity-events 我需要在用户送礼时累加活动积分
我会提供 send_gift Handler 的完整实现。
场景 2:创建定时发奖任务
/activity-events 活动结束后2小时自动发放排行奖励
我会提供延迟任务的注册和创建代码。
场景 3:添加新事件
/activity-events 我需要新增一个自定义事件
我会提供从定义到注册到发布的完整流程。