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 编写要点

  1. 入口日志:必须打印 start 日志,方便追踪
  2. 反序列化:使用 json.Unmarshal,失败时记录 error 并 return
  3. 字段校验:关键字段(uid、actId)为零值时直接 return
  4. 业务逻辑:调用 service 层处理,保持 handler 精简
  5. 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.goGetEvents() 方法

{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 我需要新增一个自定义事件

我会提供从定义到注册到发布的完整流程。

Installs
1
First Seen
Apr 16, 2026