Complete notification expiry and configurable durable delivery (#36)

This commit is contained in:
Stephan D committed 2026-09-12 14:52:44 +02:00
1 parent 326d58f705
commit 4b14649b3a
16 files changed
+320 -40

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
package bus
import (
merrors "git.sendico.io/tech/sxchnge/shared/errors"
"git.sendico.io/tech/sxchnge/shared/messaging/reliable"
)
// Config composes canonical shared messaging settings for this service's queue.
type Config struct {
Stream reliable.DurableStreamSettings `yaml:"stream"`
Provisioning reliable.DurableProvisioningSettings `yaml:"provisioning"`
}
func DefaultConfig() Config {
return Config{
Stream: reliable.DurableStreamSettings{Name: "SXCHNGE_NOTIFICATIONS", Subjects: []string{subject}, Storage: "file", MaxAgeHours: 48, Replicas: 1},
Provisioning: reliable.DurableProvisioningSettings{Mode: reliable.DurableProvisioningApp, Environment: reliable.DurableEnvironmentNonProduction},
}
}
func (c Config) Validate() error {
if c.Stream.Name != "SXCHNGE_NOTIFICATIONS" || len(c.Stream.Subjects) != 1 || c.Stream.Subjects[0] != subject || c.Stream.Storage != "file" || c.Stream.MaxAgeHours < 48 || c.Stream.MaxAgeHours > 24*30 {
return merrors.InvalidArgument("invalid notifications stream configuration")
}
if c.Stream.Replicas != 1 && c.Stream.Replicas != 3 && c.Stream.Replicas != 5 {
return merrors.InvalidArgument("stream replicas must be 1, 3 or 5")
}
switch c.Provisioning.Mode {
case reliable.DurableProvisioningApp, reliable.DurableProvisioningOps, reliable.DurableProvisioningHybrid:
default:
return merrors.InvalidArgument("invalid stream provisioning mode")
}
switch c.Provisioning.Environment {
case reliable.DurableEnvironmentProduction, reliable.DurableEnvironmentNonProduction:
default:
return merrors.InvalidArgument("invalid stream provisioning environment")
}
return nil
}
+23
View File
@@ -0,0 +1,23 @@
package bus
import (
"git.sendico.io/tech/sxchnge/shared/messaging/reliable"
"testing"
)
func TestQueueConfiguration(t *testing.T) {
config := DefaultConfig()
config.Stream.Replicas = 3
config.Provisioning.Mode = reliable.DurableProvisioningOps
config.Provisioning.Environment = reliable.DurableEnvironmentProduction
if err := config.Validate(); err != nil {
t.Fatal(err)
}
for _, change := range []func(*Config){func(c *Config) { c.Stream.Replicas = 0 }, func(c *Config) { c.Stream.Storage = "memory" }, func(c *Config) { c.Stream.MaxAgeHours = 1 }, func(c *Config) { c.Provisioning.Mode = "typo" }, func(c *Config) { c.Provisioning.Environment = "typo" }, func(c *Config) { c.Stream.Subjects = []string{"other"} }} {
c := DefaultConfig()
change(&c)
if err := c.Validate(); err == nil {
t.Fatal("invalid queue configuration accepted")
}
}
}
+5 -2
View File
@@ -29,8 +29,11 @@ type Bus struct {
logger mlogger.Logger
}
func New(ctx context.Context, transport reliable.Transport, admin reliable.Admin, outbox Outbox, handler Handler, logger mlogger.Logger) (*Bus, error) {
settings := reliable.DurableSettings{Enabled: true, Stream: reliable.DurableStreamSettings{Name: "SXCHNGE_NOTIFICATIONS", Subjects: []string{subject}, Storage: "file", MaxAgeHours: 48, Replicas: 1}, Provisioning: reliable.DurableProvisioningSettings{Mode: reliable.DurableProvisioningApp, Environment: reliable.DurableEnvironmentNonProduction}}
func New(ctx context.Context, transport reliable.Transport, admin reliable.Admin, outbox Outbox, handler Handler, logger mlogger.Logger, config Config) (*Bus, error) {
if err := config.Validate(); err != nil {
return nil, err
}
settings := reliable.DurableSettings{Enabled: true, Stream: config.Stream, Provisioning: config.Provisioning}
consumer := reliable.DurableConsumerSettings{Durable: "email", Subject: subject, AckWaitSeconds: 60, MaxDeliver: -1, DeliverPolicy: reliable.DurableDeliverAll}
if err := admin.EnsureConsumerResources(ctx, settings, consumer); err != nil {
return nil, merrors.OpaqueWrap(merrors.ErrServiceUnavailable, err, "configure notification messaging")