feat(push-gateway): config 扩展 + kafka consumer + ws handler + nextstep 文档
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
// Package kafkaconsumer subscribes to the edu.notification.requested topic
|
||||
// (ISSUE-053 final topic name) on behalf of push-gateway. Each consumed
|
||||
// Package kafkaconsumer subscribes to the edu.notify.notification.sent topic
|
||||
// (ARB-013 canonical topic name) on behalf of push-gateway. Each consumed
|
||||
// NotificationRequested event is dispatched to the Hub for delivery to online
|
||||
// clients. At-least-once delivery is enforced via manual commit; idempotency
|
||||
// is provided by Redis SETNX on event_id (TTL 24h).
|
||||
//
|
||||
// Topic naming follows the G16 rule (edu.<domain>.<aggregate>.<action>); the
|
||||
// previous abstract name edu.notification.events / edu.msg.notification.events
|
||||
// is deprecated (see president-final-rulings §1.5).
|
||||
// Topic naming follows ARB-013 (edu.<domain>.<aggregate>.<action>); the
|
||||
// previous name edu.notification.requested is deprecated (v2 alignment).
|
||||
package kafkaconsumer
|
||||
|
||||
import (
|
||||
@@ -159,12 +158,19 @@ func (c *Consumer) processMessage(ctx context.Context, msg kafka.Message) {
|
||||
if err := json.Unmarshal(msg.Value, &event); err != nil {
|
||||
observability.Logger().Warn("kafka: invalid message payload",
|
||||
"topic", c.topic, "partition", msg.Partition, "offset", msg.Offset, "err", err)
|
||||
c.metrics.IncPushed("notification.requested", "invalid")
|
||||
c.metrics.IncPushed("notification.invalid", "invalid")
|
||||
// Commit to skip the poison message.
|
||||
_ = c.reader.CommitMessages(ctx, msg)
|
||||
return
|
||||
}
|
||||
|
||||
// eventLabel is the metrics label for IncPushed. Prefer event_type (the
|
||||
// actual event name like "ExamExtended"); fall back to a generic label.
|
||||
eventLabel := event.EventType
|
||||
if eventLabel == "" {
|
||||
eventLabel = "notification.sent"
|
||||
}
|
||||
|
||||
// Idempotency: skip already-processed events by event_id.
|
||||
fresh, err := c.redis.DedupEventId(ctx, event.EventID)
|
||||
if err != nil {
|
||||
@@ -174,7 +180,7 @@ func (c *Consumer) processMessage(ctx context.Context, msg kafka.Message) {
|
||||
if !fresh {
|
||||
observability.Logger().Debug("kafka: duplicate event skipped",
|
||||
"event_id", event.EventID)
|
||||
c.metrics.IncPushed("notification.requested", "duplicate")
|
||||
c.metrics.IncPushed(eventLabel, "duplicate")
|
||||
_ = c.reader.CommitMessages(ctx, msg)
|
||||
return
|
||||
}
|
||||
@@ -182,7 +188,7 @@ func (c *Consumer) processMessage(ctx context.Context, msg kafka.Message) {
|
||||
// Retry up to MaxRetries on dispatch failure.
|
||||
for attempt := 1; attempt <= MaxRetries; attempt++ {
|
||||
if err := c.dispatch(ctx, event); err == nil {
|
||||
c.metrics.IncPushed("notification.requested", "delivered")
|
||||
c.metrics.IncPushed(eventLabel, "delivered")
|
||||
_ = c.reader.CommitMessages(ctx, msg)
|
||||
return
|
||||
} else if attempt < MaxRetries {
|
||||
@@ -195,7 +201,7 @@ func (c *Consumer) processMessage(ctx context.Context, msg kafka.Message) {
|
||||
observability.Logger().Error("kafka: dispatch failed after retries, sending to DLQ",
|
||||
"event_id", event.EventID, "topic", c.topic)
|
||||
c.sendToDLQ(ctx, msg.Value)
|
||||
c.metrics.IncPushed("notification.requested", "dlq")
|
||||
c.metrics.IncPushed(eventLabel, "dlq")
|
||||
_ = c.reader.CommitMessages(ctx, msg)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user