Files
queue/delay/redis_produce.go

117 lines
3.3 KiB
Go

// Package event ...
//
// Description : 基于redis实现事件生产 + 消费
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2025-08-22 16:34
package delay
import (
"context"
"fmt"
"os"
"time"
"git.zhangdeman.cn/zhangdeman/network/util"
"git.zhangdeman.cn/zhangdeman/queue/abstract"
"git.zhangdeman.cn/zhangdeman/queue/define"
"git.zhangdeman.cn/zhangdeman/redis"
"git.zhangdeman.cn/zhangdeman/serialize"
"git.zhangdeman.cn/zhangdeman/wrapper/op_string"
)
// NewRedisProducer 获取基于redis的生产者实例
func NewRedisProducer(
queueName string, queueCnt int, redisFlag string,
producerHandler abstract.IProducerHandler,
) abstract.IProducer {
if queueName == "" || redisFlag == "" {
panic("init redis producer: queue name or redis flag is empty")
}
// 验证redis实例是否存在
if _, err := redis.Client.GetRealClientWithError(redisFlag); nil != err {
panic(err.Error())
}
if queueCnt <= 0 {
queueCnt = 1 // 默认单队列
}
if nil == producerHandler {
producerHandler = abstract.DefaultProducerHandler{}
}
return &redisProducer{
queueCnt: queueCnt,
queueName: queueName,
redisFlag: redisFlag,
producerHandler: producerHandler,
}
}
type redisProducer struct {
redisFlag string // redis 标识, 必须是使用统一的 pkg/redis 进行管理的
queueName string // 队列名称,基础公共前缀,尾部后缀会自动根据 shard cnt 进行哈希
queueCnt int // 队列数量
producerHandler abstract.IProducerHandler // 生产数据的处理逻辑
}
// fillEventData 填充一些系统数据数据
func (r *redisProducer) fillEventData(data *define.EventData) {
if len(data.Key) == 0 {
data.Key = data.MsgID // 不设置和MsgID一致
}
if len(data.TraceID) == 0 {
data.TraceID = data.Key
}
data.SystemTimestamp = time.Now().UnixMilli() // 系统时间
if data.Timestamp <= 0 {
data.Timestamp = data.SystemTimestamp
}
data.Hostname, _ = os.Hostname() // 服务器 hostname
data.HostIp = util.IP.GetHostIP() // 服务器IP
}
// Sync 同步发送
func (r *redisProducer) Sync(ctx context.Context, data *define.EventData) {
if nil == data {
return
}
r.fillEventData(data)
realQueue := r.getRealQueue(data)
sendRedisRes := redis.Wrapper.LPush(ctx, r.redisFlag, realQueue, serialize.JSON.MarshalForStringIgnoreError(data))
res := &define.EventProduceResult{
Queue: realQueue,
Success: sendRedisRes.Err == nil,
Err: sendRedisRes.Err,
Cost: sendRedisRes.UsedTime,
}
if res.Success {
r.producerHandler.SuccessCallback(ctx, data, res)
} else {
r.producerHandler.FailureCallback(ctx, data, res)
}
}
// Async 异步发送
func (r *redisProducer) Async(ctx context.Context, data *define.EventData) {
go func() {
defer func() {
// 如果出现panic, 则触发失败回调
if err := recover(); nil != err {
r.producerHandler.PanicCallback(ctx, data, err)
}
}()
r.Sync(ctx, data)
}()
}
// GetProducerHandler 获取producer处理器
func (r *redisProducer) GetProducerHandler() abstract.IProducerHandler {
return r.producerHandler
}
// getRealQueue 获取真实的队列key
func (r *redisProducer) getRealQueue(data *define.EventData) string {
queueIdx := op_string.HashNumber(data.Key).Value % uint64(r.queueCnt)
return fmt.Sprintf("%v_%v", r.queueName, queueIdx)
}