fix: align group management APIs

This commit is contained in:
richjohnrambo
2026-09-13 16:03:55 +08:00
parent f1279ac607
commit a9afc6ff6a
34 changed files with 1381 additions and 639 deletions
+80 -5
View File
@@ -51,6 +51,17 @@ type groupFanoutEnvelope struct {
Message json.RawMessage `json:"message"`
}
type RealtimeFanoutEnvelope struct {
OriginNodeID string `json:"origin_node_id"`
TenantID types.TenantID `json:"tenant_id"`
Kind string `json:"kind"`
TargetType string `json:"target_type"`
Target string `json:"target"`
SkipSid string `json:"skip_sid,omitempty"`
DedupKey string `json:"dedup_key,omitempty"`
Message json.RawMessage `json:"message"`
}
type groupMessageRuntime interface {
Close() error
Claim(tenantID types.TenantID, topic string, from types.Uid, clientMsgID string) (*groupMessageUniqueRecord, bool, error)
@@ -71,6 +82,8 @@ type groupMessageRuntime interface {
GetTopicNodeOnlineMembers(tenantID types.TenantID, topic, nodeID string) ([]types.Uid, error)
PublishGroupFanout(originNodeID string, message any) error
StartGroupFanoutSubscriber(ctx context.Context, nodeID string, handler func([]byte)) error
PublishRealtimeFanout(originNodeID string, tenantID types.TenantID, kind, targetType, target, skipSid, dedupKey string, message any) error
StartRealtimeFanoutSubscriber(ctx context.Context, nodeID string, handler func(*RealtimeFanoutEnvelope)) error
CacheObject(tenantID types.TenantID, namespace, id string, value any) error
GetCachedObject(tenantID types.TenantID, namespace, id string, value any) (bool, error)
DeleteCachedObject(tenantID types.TenantID, namespace, id string) error
@@ -237,6 +250,20 @@ func StartGroupFanoutSubscriber(ctx context.Context, nodeID string, handler func
return groupMsgRuntime.StartGroupFanoutSubscriber(ctx, nodeID, handler)
}
func PublishRealtimeFanout(originNodeID string, tenantID types.TenantID, kind, targetType, target, skipSid, dedupKey string, message any) error {
if groupMsgRuntime == nil || originNodeID == "" || !tenantID.IsValid() || targetType == "" || target == "" || message == nil {
return nil
}
return groupMsgRuntime.PublishRealtimeFanout(originNodeID, tenantID, kind, targetType, target, skipSid, dedupKey, message)
}
func StartRealtimeFanoutSubscriber(ctx context.Context, nodeID string, handler func(*RealtimeFanoutEnvelope)) error {
if groupMsgRuntime == nil || nodeID == "" || handler == nil {
return nil
}
return groupMsgRuntime.StartRealtimeFanoutSubscriber(ctx, nodeID, handler)
}
func CacheObject(tenantID types.TenantID, namespace, id string, value any) error {
if groupMsgRuntime == nil || !tenantID.IsValid() || namespace == "" || id == "" || value == nil {
return nil
@@ -761,28 +788,49 @@ func (r *redisGroupMessageRuntime) GetTopicNodeOnlineMembers(tenantID types.Tena
}
func (r *redisGroupMessageRuntime) PublishGroupFanout(originNodeID string, message any) error {
return r.PublishRealtimeFanout(originNodeID, types.ZeroTenantID, "message", "topic", "", "", "", message)
}
func (r *redisGroupMessageRuntime) PublishRealtimeFanout(originNodeID string, tenantID types.TenantID, kind, targetType, target, skipSid, dedupKey string, message any) error {
if !r.cfg.GroupFanout {
return nil
}
if originNodeID == "" || message == nil {
return nil
}
payload, err := json.Marshal(message)
if err != nil {
return err
}
envelope, err := json.Marshal(groupFanoutEnvelope{
envelope, err := json.Marshal(RealtimeFanoutEnvelope{
OriginNodeID: originNodeID,
TenantID: tenantID,
Kind: kind,
TargetType: targetType,
Target: target,
SkipSid: skipSid,
DedupKey: dedupKey,
Message: payload,
})
if err != nil {
return err
}
return r.client.Publish(context.Background(), r.groupFanoutChannel(), envelope).Err()
return r.client.Publish(context.Background(), r.realtimeFanoutChannel(tenantID), envelope).Err()
}
func (r *redisGroupMessageRuntime) StartGroupFanoutSubscriber(ctx context.Context, nodeID string, handler func([]byte)) error {
return r.StartRealtimeFanoutSubscriber(ctx, nodeID, func(envelope *RealtimeFanoutEnvelope) {
if envelope != nil {
handler(envelope.Message)
}
})
}
func (r *redisGroupMessageRuntime) StartRealtimeFanoutSubscriber(ctx context.Context, nodeID string, handler func(*RealtimeFanoutEnvelope)) error {
if !r.cfg.GroupFanout {
return nil
}
pubsub := r.client.Subscribe(ctx, r.groupFanoutChannel())
pubsub := r.client.PSubscribe(ctx, r.realtimeFanoutPattern())
if _, err := pubsub.Receive(ctx); err != nil {
_ = pubsub.Close()
return err
@@ -798,11 +846,27 @@ func (r *redisGroupMessageRuntime) StartGroupFanoutSubscriber(ctx context.Contex
if !ok {
return
}
var envelope groupFanoutEnvelope
var envelope RealtimeFanoutEnvelope
if err := json.Unmarshal([]byte(msg.Payload), &envelope); err != nil || envelope.OriginNodeID == nodeID || len(envelope.Message) == 0 {
continue
}
handler(envelope.Message)
if envelope.TenantID.IsValid() && envelope.DedupKey != "" {
id := fmt.Sprintf("%d:%s", envelope.TenantID, envelope.DedupKey)
claimed, err := r.ClaimShortState("rt_dedup", id, 5*time.Minute)
if err != nil || !claimed {
continue
}
}
if envelope.TargetType == "" {
envelope.TargetType = "topic"
}
if envelope.Kind == "" {
envelope.Kind = "message"
}
if !envelope.TenantID.IsValid() && envelope.Target == "" {
continue
}
handler(&envelope)
}
}
}()
@@ -1035,6 +1099,17 @@ func (r *redisGroupMessageRuntime) groupFanoutChannel() string {
return r.key(types.ZeroTenantID, "group_fanout")
}
func (r *redisGroupMessageRuntime) realtimeFanoutChannel(tenantID types.TenantID) string {
if tenantID.IsValid() {
return r.key(tenantID, "rt", "fanout")
}
return r.groupFanoutChannel()
}
func (r *redisGroupMessageRuntime) realtimeFanoutPattern() string {
return strings.TrimSuffix(r.prefix, ":") + ":*:rt:fanout"
}
func (r *redisGroupMessageRuntime) objectCacheKey(tenantID types.TenantID, namespace, id string) string {
return r.key(tenantID, "cache", namespace, id)
}