Refine Kafka persistence topic boundaries

This commit is contained in:
richjohnrambo
2026-09-01 23:23:08 +08:00
parent f8a286cec2
commit 318ce04f7d
13 changed files with 294 additions and 252 deletions
+17 -50
View File
@@ -5,8 +5,6 @@ import (
"encoding/json"
"time"
"github.com/segmentio/kafka-go"
"github.com/tinode/chat/server/store"
"github.com/tinode/chat/server/store/types"
)
@@ -34,15 +32,10 @@ type kafkaAuditPayload struct {
OccurredAt time.Time `json:"occurred_at"`
}
func startKafkaWorkbenchEventConsumer() {
startKafkaConsumer("workbench_event", handleKafkaWorkbenchEvent)
}
var publishKafkaAuditEventEnvelope = publishKafkaEnvelope
func enqueueKafkaWorkbenchEvent(ctx context.Context, tenantID types.TenantID, actor types.Uid, module, action, resourceID string,
targets []types.Uid, title, summary string, data map[string]any) error {
if !kafkaEnabled() {
return nil
}
targetUserIDs := make([]string, 0, len(targets))
for _, target := range targets {
if !target.IsZero() {
@@ -60,7 +53,14 @@ func enqueueKafkaWorkbenchEvent(ctx context.Context, tenantID types.TenantID, ac
Data: data,
OccurredAt: time.Now().UTC().Round(time.Millisecond),
}
return enqueueKafkaTypedEvent(ctx, tenantID, "workbench_event", "workbench."+action, "workbench", resourceID, actor, payload)
envelope := kafkaEnvelope{
EventID: stableIMEventID("workbench-sync", tenantID, "workbench."+action, resourceID, payload.OccurredAt),
TenantID: tenantID,
EventType: "workbench." + action,
BizType: "workbench",
BizID: resourceID,
}
return executeKafkaWorkbenchEvent(tenantID, envelope, payload)
}
func enqueueKafkaAuditEvent(ctx context.Context, tenantID types.TenantID, actorType string, actor types.Uid,
@@ -83,58 +83,25 @@ func enqueueKafkaAuditEvent(ctx context.Context, tenantID types.TenantID, actorT
Data: data,
OccurredAt: time.Now().UTC().Round(time.Millisecond),
}
return enqueueKafkaTypedEvent(ctx, tenantID, "audit_event", "audit."+action, "audit", resource+":"+resourceID, actor, payload)
}
func enqueueKafkaTypedEvent(ctx context.Context, tenantID types.TenantID, topicName, eventType, bizType, bizID string, actor types.Uid, payload any) error {
encoded, err := json.Marshal(payload)
if err != nil {
return err
}
eventID := stableIMEventID(topicName, tenantID, eventType, bizID, encoded)
envelope := kafkaEnvelope{
EventID: eventID,
EventID: stableIMEventID("audit_event", tenantID, "audit."+action, resource+":"+resourceID, encoded),
TenantID: tenantID,
SourceService: "im-server",
TargetService: "im-server",
EventType: eventType,
BizType: bizType,
BizID: bizID,
OccurredAt: time.Now().UTC(),
TargetService: "hotgo-admin",
EventType: "audit." + action,
BizType: "audit",
BizID: resource + ":" + resourceID,
OccurredAt: payload.OccurredAt,
Payload: encoded,
}
if !actor.IsZero() {
envelope.Actor = &kafkaActor{Type: "user", ID: actor.UserId()}
envelope.Actor = &kafkaActor{Type: actorType, ID: actorID}
}
return publishKafkaEnvelope(ctx, topicName, bizID, envelope)
}
func handleKafkaWorkbenchEvent(ctx context.Context, envelope kafkaEnvelope, _ kafka.Message) error {
tenantID, err := kafkaTenantIDFromEnvelope(envelope)
if err != nil {
return err
}
consume, claimed, err := beginKafkaConsumeForTopic(tenantID, envelope, "workbench_event")
if err != nil || !claimed {
return err
}
var payload kafkaWorkbenchPayload
if err = json.Unmarshal(envelope.Payload, &payload); err != nil {
return markKafkaDeadLetter(ctx, tenantID, envelope, consume, "MALFORMED_PAYLOAD", err.Error())
}
if err = executeKafkaWorkbenchEvent(tenantID, envelope, payload); err != nil {
failed, markErr := store.HTTPInfrastructure.MarkKafkaConsumeFailed(tenantID, envelope.EventID, kafkaBus.config.ConsumerGroup,
kafkaCommandErrorReason(err), err.Error(), time.Now().UTC().Round(time.Millisecond))
if markErr != nil {
return markErr
}
if failed != nil && failed.RetryCount >= kafkaBus.config.MaxRetryCount {
return markKafkaDeadLetter(ctx, tenantID, envelope, failed, kafkaCommandErrorReason(err), err.Error())
}
sleepKafkaRetryBackoff(failed.RetryCount)
return err
}
return store.HTTPInfrastructure.MarkKafkaConsumeSucceeded(tenantID, envelope.EventID, kafkaBus.config.ConsumerGroup, time.Now().UTC().Round(time.Millisecond))
return publishKafkaAuditEventEnvelope(ctx, "audit_event", envelope.BizID, envelope)
}
func executeKafkaWorkbenchEvent(tenantID types.TenantID, envelope kafkaEnvelope, payload kafkaWorkbenchPayload) error {