Update Go module dependencies and enhance NATS consumer metrics. Add github.com/kylelemons/godebug as an indirect dependency. Upgrade github.com/prometheus/common to version 0.67.3. Change NATS consumer mode to "jetstream" in the development configuration. Improve observability by ensuring metrics for pending messages are initialized and recorded correctly in JetStream mode. Update documentation to reflect changes in metrics handling and consumer behavior.

This commit is contained in:
windyboy
2025-11-19 16:49:53 +08:00
parent f01dd3bf1f
commit 8914156a58
10 changed files with 261 additions and 49 deletions
+68 -9
View File
@@ -1,7 +1,9 @@
package nats
import (
"errors"
"fmt"
"time"
"github.com/nats-io/nats.go"
"go.uber.org/zap"
@@ -15,6 +17,16 @@ type StreamManager struct {
logger *zap.Logger
}
// StreamConfig holds configuration for creating a JetStream stream
type StreamConfig struct {
MaxMsgs int64
MaxBytes int64
MaxAge time.Duration
Discard string // "old" or "new"
Storage string // "file" or "memory"
Replicas int
}
// NewStreamManager creates a new stream manager
func NewStreamManager(js nats.JetStreamContext, streamName string, subjects []string, logger *zap.Logger) *StreamManager {
return &StreamManager{
@@ -25,16 +37,63 @@ func NewStreamManager(js nats.JetStreamContext, streamName string, subjects []st
}
}
// EnsureStream ensures that the configured JetStream stream exists
func (sm *StreamManager) EnsureStream() error {
// EnsureStream ensures that the configured JetStream stream exists, creating it if necessary
func (sm *StreamManager) EnsureStream(cfg *StreamConfig) error {
// Check if stream already exists
_, err := sm.js.StreamInfo(sm.streamName)
if err != nil {
return fmt.Errorf("stream %s not found or inaccessible: %w", sm.streamName, err)
if err == nil {
sm.logger.Info("JetStream stream verified",
zap.String("stream", sm.streamName),
zap.Strings("subjects", sm.subjects),
)
return nil
}
sm.logger.Info("JetStream stream verified",
zap.String("stream", sm.streamName),
zap.Strings("subjects", sm.subjects),
)
return nil
// If stream doesn't exist, create it
if errors.Is(err, nats.ErrStreamNotFound) {
streamCfg := &nats.StreamConfig{
Name: sm.streamName,
Subjects: sm.subjects,
}
// Apply limits if provided
if cfg != nil {
if cfg.MaxMsgs > 0 {
streamCfg.MaxMsgs = cfg.MaxMsgs
}
if cfg.MaxBytes > 0 {
streamCfg.MaxBytes = cfg.MaxBytes
}
if cfg.MaxAge > 0 {
streamCfg.MaxAge = cfg.MaxAge
}
if cfg.Discard == "new" {
streamCfg.Discard = nats.DiscardNew
} else {
streamCfg.Discard = nats.DiscardOld
}
if cfg.Storage == "memory" {
streamCfg.Storage = nats.MemoryStorage
} else {
streamCfg.Storage = nats.FileStorage
}
if cfg.Replicas > 0 {
streamCfg.Replicas = cfg.Replicas
}
}
_, err := sm.js.AddStream(streamCfg)
if err != nil {
return fmt.Errorf("failed to create stream %s: %w", sm.streamName, err)
}
sm.logger.Info("Created JetStream stream",
zap.String("stream", sm.streamName),
zap.Strings("subjects", sm.subjects),
)
return nil
}
// Other error (e.g., permission denied)
return fmt.Errorf("stream %s not found or inaccessible: %w", sm.streamName, err)
}