Make configuration values injectable rather than hardcoded
Add config structs with sensible defaults for tunable parameters: - JetStreamConfig for stream retention (1 year) and replica count (1) - HashRingConfig for virtual nodes per physical node (150) - ShardConfig for shard count (1024) and replication factor (1) Each component gets a new WithConfig constructor that accepts custom configuration, while the original constructors continue to work with defaults. Zero values in configs fall back to defaults for backward compatibility. Closes #38 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit was merged in pull request #43.
This commit is contained in:
46
store/config_test.go
Normal file
46
store/config_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDefaultJetStreamConfig(t *testing.T) {
|
||||
config := DefaultJetStreamConfig()
|
||||
|
||||
if config.StreamRetention != DefaultStreamRetention {
|
||||
t.Errorf("expected StreamRetention=%v, got %v", DefaultStreamRetention, config.StreamRetention)
|
||||
}
|
||||
if config.ReplicaCount != DefaultReplicaCount {
|
||||
t.Errorf("expected ReplicaCount=%d, got %d", DefaultReplicaCount, config.ReplicaCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJetStreamConfigDefaults(t *testing.T) {
|
||||
t.Run("default stream retention is 1 year", func(t *testing.T) {
|
||||
expected := 365 * 24 * time.Hour
|
||||
if DefaultStreamRetention != expected {
|
||||
t.Errorf("expected DefaultStreamRetention=%v, got %v", expected, DefaultStreamRetention)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("default replica count is 1", func(t *testing.T) {
|
||||
if DefaultReplicaCount != 1 {
|
||||
t.Errorf("expected DefaultReplicaCount=1, got %d", DefaultReplicaCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestJetStreamConfigCustomValues(t *testing.T) {
|
||||
config := JetStreamConfig{
|
||||
StreamRetention: 30 * 24 * time.Hour, // 30 days
|
||||
ReplicaCount: 3,
|
||||
}
|
||||
|
||||
if config.StreamRetention != 30*24*time.Hour {
|
||||
t.Errorf("expected StreamRetention=30 days, got %v", config.StreamRetention)
|
||||
}
|
||||
if config.ReplicaCount != 3 {
|
||||
t.Errorf("expected ReplicaCount=3, got %d", config.ReplicaCount)
|
||||
}
|
||||
}
|
||||
@@ -11,29 +11,65 @@ import (
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
// Default configuration values for JetStream event store
|
||||
const (
|
||||
DefaultStreamRetention = 365 * 24 * time.Hour // 1 year
|
||||
DefaultReplicaCount = 1
|
||||
)
|
||||
|
||||
// JetStreamConfig holds configuration options for JetStreamEventStore
|
||||
type JetStreamConfig struct {
|
||||
// StreamRetention is how long to keep events (default: 1 year)
|
||||
StreamRetention time.Duration
|
||||
// ReplicaCount is the number of replicas for high availability (default: 1)
|
||||
ReplicaCount int
|
||||
}
|
||||
|
||||
// DefaultJetStreamConfig returns the default configuration
|
||||
func DefaultJetStreamConfig() JetStreamConfig {
|
||||
return JetStreamConfig{
|
||||
StreamRetention: DefaultStreamRetention,
|
||||
ReplicaCount: DefaultReplicaCount,
|
||||
}
|
||||
}
|
||||
|
||||
// JetStreamEventStore implements EventStore using NATS JetStream for persistence
|
||||
type JetStreamEventStore struct {
|
||||
js nats.JetStreamContext
|
||||
streamName string
|
||||
mu sync.Mutex // Protects version checks during SaveEvent
|
||||
versions map[string]int64 // actorID -> latest version cache
|
||||
config JetStreamConfig
|
||||
mu sync.Mutex // Protects version checks during SaveEvent
|
||||
versions map[string]int64 // actorID -> latest version cache
|
||||
}
|
||||
|
||||
// NewJetStreamEventStore creates a new JetStream-based event store
|
||||
// NewJetStreamEventStore creates a new JetStream-based event store with default configuration
|
||||
func NewJetStreamEventStore(natsConn *nats.Conn, streamName string) (*JetStreamEventStore, error) {
|
||||
return NewJetStreamEventStoreWithConfig(natsConn, streamName, DefaultJetStreamConfig())
|
||||
}
|
||||
|
||||
// NewJetStreamEventStoreWithConfig creates a new JetStream-based event store with custom configuration
|
||||
func NewJetStreamEventStoreWithConfig(natsConn *nats.Conn, streamName string, config JetStreamConfig) (*JetStreamEventStore, error) {
|
||||
js, err := natsConn.JetStream()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get JetStream context: %w", err)
|
||||
}
|
||||
|
||||
// Apply defaults for zero values
|
||||
if config.StreamRetention == 0 {
|
||||
config.StreamRetention = DefaultStreamRetention
|
||||
}
|
||||
if config.ReplicaCount == 0 {
|
||||
config.ReplicaCount = DefaultReplicaCount
|
||||
}
|
||||
|
||||
// Create or update the stream
|
||||
stream := &nats.StreamConfig{
|
||||
Name: streamName,
|
||||
Subjects: []string{fmt.Sprintf("%s.events.>", streamName), fmt.Sprintf("%s.snapshots.>", streamName)},
|
||||
Storage: nats.FileStorage,
|
||||
Retention: nats.LimitsPolicy,
|
||||
MaxAge: 365 * 24 * time.Hour, // Keep events for 1 year
|
||||
Replicas: 1, // Can be increased for HA
|
||||
MaxAge: config.StreamRetention,
|
||||
Replicas: config.ReplicaCount,
|
||||
}
|
||||
|
||||
_, err = js.AddStream(stream)
|
||||
@@ -44,6 +80,7 @@ func NewJetStreamEventStore(natsConn *nats.Conn, streamName string) (*JetStreamE
|
||||
return &JetStreamEventStore{
|
||||
js: js,
|
||||
streamName: streamName,
|
||||
config: config,
|
||||
versions: make(map[string]int64),
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user