feat: complete IM P0 and P1 reliability work
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/tinode/chat/server/logs"
|
||||
"github.com/tinode/chat/server/store"
|
||||
"github.com/tinode/chat/server/store/types"
|
||||
)
|
||||
|
||||
// dispatchIMGroupEvents delivers committed outbox events to online topic
|
||||
// sessions. Events remain pending when the hub is unavailable or its queue is
|
||||
// full, so the next successful group mutation retries them.
|
||||
func dispatchIMGroupEvents(tenantID types.TenantID) {
|
||||
if tenantID.IsZero() || globals.hub == nil || store.GroupBusiness == nil {
|
||||
return
|
||||
}
|
||||
now := time.Now().UTC().Round(time.Millisecond)
|
||||
events, err := store.GroupBusiness.ListPendingEvents(tenantID, 100, now)
|
||||
if err != nil {
|
||||
logs.Warn.Printf("group outbox: list tenant=%d: %v", tenantID, err)
|
||||
return
|
||||
}
|
||||
for _, event := range events {
|
||||
members, memberErr := store.Topics.GetUsers(tenantID, event.Topic, &types.QueryOpt{Limit: 1000})
|
||||
if memberErr != nil {
|
||||
logs.Warn.Printf("group outbox: list members event=%s: %v", event.EventID, memberErr)
|
||||
return
|
||||
}
|
||||
for _, member := range members {
|
||||
uid := types.ParseUid(member.User)
|
||||
if uid.IsZero() {
|
||||
if decoded, parseErr := strconv.ParseInt(member.User, 10, 64); parseErr == nil && decoded > 0 {
|
||||
uid = store.EncodeUid(decoded)
|
||||
}
|
||||
}
|
||||
if uid.IsZero() || uid == event.ActorUserID {
|
||||
continue
|
||||
}
|
||||
if err = createIMSystemNotification(tenantID, uid,
|
||||
stableIMEventID(event.EventID, uid.UserId(), "notification"), event.EventType,
|
||||
"群聊动态", event.EventType, types.KVMap{"topic": event.Topic}); err != nil {
|
||||
logs.Warn.Printf("group outbox: create notification event=%s user=%s: %v", event.EventID, uid.UserId(), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
payload := json.RawMessage(event.Payload)
|
||||
if len(payload) == 0 {
|
||||
payload = json.RawMessage(`{}`)
|
||||
}
|
||||
from := ""
|
||||
if !event.ActorUserID.IsZero() {
|
||||
from = event.ActorUserID.UserId()
|
||||
}
|
||||
message := &ServerComMessage{
|
||||
TenantID: tenantID,
|
||||
RcptTo: event.Topic,
|
||||
AsUser: from,
|
||||
Timestamp: event.CreatedAt,
|
||||
Info: &MsgServerInfo{
|
||||
Topic: event.Topic,
|
||||
From: from,
|
||||
What: "group",
|
||||
Event: event.EventType,
|
||||
Payload: payload,
|
||||
},
|
||||
}
|
||||
select {
|
||||
case globals.hub.routeSrv <- message:
|
||||
if err = store.GroupBusiness.MarkEventDelivered(tenantID, event.EventID, now); err != nil {
|
||||
logs.Warn.Printf("group outbox: mark delivered event=%s: %v", event.EventID, err)
|
||||
return
|
||||
}
|
||||
default:
|
||||
logs.Warn.Printf("group outbox: hub queue full event=%s", event.EventID)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user