From 6d2d6c38ec0b7b3bf9ab4cbd0bfcd67beabd480f Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Wed, 29 Jul 2026 11:53:58 +0200 Subject: [PATCH] fix: fail fast when the announcement store is unreachable Replace reva's cache.NewNatsKeyValue (which retries with backoff and can hang the web service startup) with a direct nats.Connect + jetstream setup like the graph service, so an unreachable or misconfigured store surfaces as a clear startup error instead of a hang. --- services/web/pkg/server/http/server.go | 39 ++++++++++++++++++-------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/services/web/pkg/server/http/server.go b/services/web/pkg/server/http/server.go index 13c21ec8aa..0b9621c798 100644 --- a/services/web/pkg/server/http/server.go +++ b/services/web/pkg/server/http/server.go @@ -1,16 +1,20 @@ package http import ( + "errors" "fmt" "path" + "strings" chimiddleware "github.com/go-chi/chi/v5/middleware" + "github.com/nats-io/nats.go" + "github.com/nats-io/nats.go/jetstream" "github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool" - "github.com/opencloud-eu/reva/v2/pkg/storage/cache" "go-micro.dev/v4" "github.com/opencloud-eu/opencloud/pkg/cors" "github.com/opencloud-eu/opencloud/pkg/middleware" + natspkg "github.com/opencloud-eu/opencloud/pkg/nats" "github.com/opencloud-eu/opencloud/pkg/registry" "github.com/opencloud-eu/opencloud/pkg/service/http" "github.com/opencloud-eu/opencloud/pkg/version" @@ -78,18 +82,29 @@ func Server(opts ...Option) (http.Service, error) { fsx.NewBasePathFs(fsx.FromIOFS(web.Assets), "assets/themes"), ) - // NATS JetStream key-value store for runtime managed web settings, e.g. the announcement banner - kv, err := cache.NewNatsKeyValue(cache.Config{ - Nodes: options.Config.Store.Nodes, - Database: options.Config.Store.Database, - AuthUsername: options.Config.Store.AuthUsername, - AuthPassword: options.Config.Store.AuthPassword, - TLSEnabled: options.Config.Store.EnableTLS, - TLSInsecure: options.Config.Store.TLSInsecure, - TLSRootCACertificate: options.Config.Store.TLSRootCACertificate, - }, &options.Logger.Logger) + // NATS JetStream key-value store for runtime managed web settings, e.g. the announcement banner. + // Connect eagerly and fail fast: an unreachable store means the feature would be broken, so a + // clear startup error is preferable to silently degrading. + natsConn, err := nats.Connect( + strings.Join(options.Config.Store.Nodes, ","), + natspkg.Secure(options.Config.Store.EnableTLS, options.Config.Store.TLSInsecure, options.Config.Store.TLSRootCACertificate), + nats.UserInfo(options.Config.Store.AuthUsername, options.Config.Store.AuthPassword), + ) if err != nil { - return http.Service{}, fmt.Errorf("could not initialize announcement store: %w", err) + return http.Service{}, fmt.Errorf("could not connect to nats for the announcement store: %w", err) + } + js, err := jetstream.New(natsConn) + if err != nil { + return http.Service{}, fmt.Errorf("could not create jetstream context for the announcement store: %w", err) + } + kv, err := js.KeyValue(options.Context, options.Config.Store.Database) + if err != nil { + if !errors.Is(err, jetstream.ErrBucketNotFound) { + return http.Service{}, fmt.Errorf("could not open the announcement store bucket %q: %w", options.Config.Store.Database, err) + } + if kv, err = js.CreateKeyValue(options.Context, jetstream.KeyValueConfig{Bucket: options.Config.Store.Database}); err != nil { + return http.Service{}, fmt.Errorf("could not create the announcement store bucket %q: %w", options.Config.Store.Database, err) + } } announcementStore := announcement.NewStore(kv)