Refactor Kafka publishing without DB outbox

This commit is contained in:
richjohnrambo
2026-09-01 23:00:14 +08:00
parent 18237cf3ec
commit 929f847003
25 changed files with 416 additions and 478 deletions
+47
View File
@@ -6,10 +6,57 @@ import (
"strings"
"time"
"github.com/segmentio/kafka-go"
"github.com/tinode/chat/server/logs"
"github.com/tinode/chat/server/store"
"github.com/tinode/chat/server/store/types"
)
func startKafkaDeadLetterConsumer() {
startKafkaConsumer("dead_letter", handleKafkaDeadLetter)
}
func handleKafkaDeadLetter(ctx context.Context, envelope kafkaEnvelope, _ kafka.Message) error {
var dead types.KafkaDeadLetter
if err := json.Unmarshal(envelope.Payload, &dead); err != nil {
return err
}
if dead.DeadID == "" {
dead.DeadID = envelope.EventID
}
tenantID, err := tenantIDFromDeadLetter(envelope, &dead)
if err != nil {
return err
}
now := time.Now().UTC().Round(time.Millisecond)
if err = store.HTTPInfrastructure.MarkKafkaConsumeDead(tenantID, &dead, now); err != nil {
return err
}
if auditErr := enqueueKafkaAuditEvent(ctx, tenantID, "system", types.ZeroUid, "kafka.dead_letter.created", "kafka_event", dead.EventID, "dead", dead.LastReason, map[string]any{
"dead_id": dead.DeadID,
"event_type": dead.EventType,
"biz_type": dead.BizType,
"biz_id": dead.BizID,
"consumer_group": dead.ConsumerGroup,
}); auditErr != nil {
logs.Warn.Printf("kafka dead letter audit enqueue failed: event=%s dead=%s err=%v", dead.EventID, dead.DeadID, auditErr)
}
return nil
}
func tenantIDFromDeadLetter(envelope kafkaEnvelope, dead *types.KafkaDeadLetter) (types.TenantID, error) {
if !envelope.TenantID.IsZero() {
return envelope.TenantID, nil
}
if dead != nil && len(dead.Envelope) > 0 {
var original kafkaEnvelope
if err := json.Unmarshal(dead.Envelope, &original); err == nil && !original.TenantID.IsZero() {
return original.TenantID, nil
}
}
return kafkaTenantID(envelope.TenantCode)
}
func replayKafkaDeadLetter(ctx context.Context, tenantID types.TenantID, deadID string, actor types.Uid, note string) (*types.KafkaDeadLetter, error) {
now := time.Now().UTC().Round(time.Millisecond)
dead, err := store.HTTPInfrastructure.MarkKafkaDeadLetterReplay(tenantID, deadID, actor.UserId(), note, now)