feat(push-gateway,msg): redis pubsub backplane for real-time notifications
M7: ADR-040 Redis Pub/Sub as state routing backplane
- push-gateway: remove Kafka consumer, add SSE endpoint
- SSE: subscribe to Redis user:{userId}:notify on connect
- msg: publish notifications to Redis Pub/Sub instead of HTTP push
- docker-compose: remove Kafka env from push-gateway
This commit is contained in:
@@ -2,9 +2,11 @@
|
||||
// variables. Required variables (JWT_SECRET in production, PUSH_INTERNAL_TOKEN
|
||||
// or INTERNAL_API_TOKEN when not in DevMode) cause a fatal exit when missing.
|
||||
//
|
||||
// v2 alignment (ARB-013 / msg contract): Kafka topic default changed to
|
||||
// edu.notify.notification.sent; PUSH_INTERNAL_TOKEN is the canonical env var
|
||||
// for /internal/* auth (INTERNAL_API_TOKEN kept as a backward-compat alias).
|
||||
// M7 (ADR-040): Kafka config removed — push-gateway no longer mounts Kafka
|
||||
// directly. Real-time push is routed through Redis Pub/Sub backplane
|
||||
// (channel: user:{userId}:notify). PUSH_INTERNAL_TOKEN is the canonical env
|
||||
// var for /internal/* auth (INTERNAL_API_TOKEN kept as a backward-compat
|
||||
// alias).
|
||||
package config
|
||||
|
||||
import (
|
||||
@@ -29,10 +31,6 @@ type Config struct {
|
||||
HeartbeatInterval int // seconds
|
||||
// JWT RS256 (via shared-go/jwks, iam /.well-known/jwks.json)
|
||||
JWKSURL string
|
||||
// Kafka
|
||||
KafkaBrokers []string
|
||||
KafkaNotificationTopic string
|
||||
KafkaConsumerGroup string
|
||||
// Instance identity (for Redis SET membership)
|
||||
InstanceID string
|
||||
}
|
||||
@@ -80,11 +78,6 @@ func Load() *Config {
|
||||
MaxConnsPerUser: env.GetInt("MAX_CONNS_PER_USER", 5),
|
||||
HeartbeatInterval: env.GetInt("HEARTBEAT_INTERVAL_SECONDS", 30),
|
||||
JWKSURL: env.Get("JWKS_URL", "http://localhost:50052/.well-known/jwks.json"),
|
||||
KafkaBrokers: parseBrokers(env.Get("KAFKA_BROKERS", "localhost:9092")),
|
||||
// ARB-013 canonical topic name: edu.<domain>.<aggregate>.<action>.
|
||||
// msg's Outbox publisher emits to this topic.
|
||||
KafkaNotificationTopic: env.Get("KAFKA_NOTIFICATION_TOPIC", "edu.notify.notification.sent"),
|
||||
KafkaConsumerGroup: env.Get("KAFKA_CONSUMER_GROUP", "push-gateway"),
|
||||
InstanceID: env.Get("INSTANCE_ID", generateInstanceID()),
|
||||
}
|
||||
}
|
||||
@@ -105,18 +98,6 @@ func parseOrigins(raw string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// parseBrokers splits a comma-separated list of Kafka broker addresses.
|
||||
func parseBrokers(raw string) []string {
|
||||
parts := strings.Split(raw, ",")
|
||||
out := make([]string, 0, len(parts))
|
||||
for _, p := range parts {
|
||||
if trimmed := strings.TrimSpace(p); trimmed != "" {
|
||||
out = append(out, trimmed)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// generateInstanceID returns a stable process-unique identifier. Falls back to
|
||||
// the hostname when INSTANCE_ID is not explicitly set, allowing each replica to
|
||||
// be uniquely identifiable in the Redis online-presence SET.
|
||||
|
||||
Reference in New Issue
Block a user