From 5de39c4125a4d33c29856f36b7fb84a56aaf5cb5 Mon Sep 17 00:00:00 2001 From: Rodrigo Broggi Date: Wed, 24 Jul 2024 18:01:47 +0200 Subject: [PATCH] on-update functionality in example --- Makefile | 16 ++++++++-- README.md | 10 +++--- example/app/main.go | 64 +++++++++++++++++++++++++++++++++++++ example/config/config.go | 27 ++++++++++++++++ example/server/configs.http | 7 ++-- example/server/main.go | 22 ++----------- example/server/server.go | 7 ++-- 7 files changed, 120 insertions(+), 33 deletions(-) create mode 100644 example/app/main.go create mode 100644 example/config/config.go diff --git a/Makefile b/Makefile index 51b1ada..1841cb8 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,18 @@ dependencies_up: dependencies_down tests: go test -v ./... -.PHONY: example +.PHONY: build-example ## example: runs an http-server locally -example: +build-example: go build -o bin/server github.com/rbroggi/streamingconfig/example/server - ./bin/server \ No newline at end of file + go build -o bin/app github.com/rbroggi/streamingconfig/example/app + +.PHONY: run-example-server +## run-example-server: runs an http-server locally +run-example-server: build-example + ./bin/server + +.PHONY: run-example-app +## run-example-app: runs an http-server locally +run-example-app: build-example + ./bin/app diff --git a/README.md b/README.md index 4b17ca6..2f47bfd 100644 --- a/README.md +++ b/README.md @@ -109,17 +109,17 @@ make dependencies_up make tests ``` -### Run example server +### Run example +Start by starting the dependencies (mongo), and run the example-server which is a simple HTTP server to receive GET,POST requests for reading/updating configurations. ```shell make dependencies_up -make example +make run-example-server ``` - -Optionally, you can also start a second server to check that the changes happening in one server will be reflected in the other: +on a different shell, run the sample APP, which is an app that receives changes upon changes that happen in the configuration through the server API endpoints. ```shell -HTTP_PORT=8081 make example +make run-example-app ``` #### Getting latest configuration request diff --git a/example/app/main.go b/example/app/main.go new file mode 100644 index 0000000..713203d --- /dev/null +++ b/example/app/main.go @@ -0,0 +1,64 @@ +package main + +import ( + "context" + "fmt" + "log" + "log/slog" + "os" + "os/signal" + "syscall" + "time" + + config "github.com/rbroggi/streamingconfig" + appcfg "github.com/rbroggi/streamingconfig/example/config" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func main() { + runnableCtx, cancelRunnables := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer cancelRunnables() + _, done := initRepo(runnableCtx) + // until shutdown signal is sent + <-runnableCtx.Done() + <-done +} + +func initRepo(ctx context.Context) (*config.WatchedRepo[*appcfg.Conf], <-chan struct{}) { + lgr := slog.Default() + db := getDb() + repo, err := config.NewWatchedRepo[*appcfg.Conf]( + config.Args{ + Logger: lgr, + DB: db, + }, config.WithOnUpdate[*appcfg.Conf](func(conf *appcfg.Conf) { + lgr.With("cfg", conf).Debug("config updated") + slog.SetLogLoggerLevel(conf.LogLevel) + })) + if err != nil { + log.Fatal(err) + } + done, err := repo.Start(ctx) + if err != nil { + log.Fatal(err) + } + return repo, done +} + +func getDb() *mongo.Database { + ctx, cnl := context.WithTimeout(context.Background(), 5*time.Second) + defer cnl() + // use test name as db name to parallel tests. + opts := options.Client() + opts.ApplyURI("mongodb://localhost:27017/?connect=direct") + client, err := mongo.Connect(ctx, opts) + if err != nil { + panic(fmt.Errorf("run `make dependencies_up` before, error: %w", err)) + } + err = client.Ping(ctx, nil) + if err != nil { + panic(fmt.Errorf("error %v\nrun `make dependencies_up` before running main\n", err)) + } + return client.Database("test") +} diff --git a/example/config/config.go b/example/config/config.go new file mode 100644 index 0000000..e0158f7 --- /dev/null +++ b/example/config/config.go @@ -0,0 +1,27 @@ +package config + +import ( + "errors" + "log/slog" + + config "github.com/rbroggi/streamingconfig" +) + +type Conf struct { + LogLevel slog.Level `json:"logLevel" default:"\"DEBUG\""` + Name string `json:"name" default:"john"` + Age int `json:"age"` + Friends []string `json:"friends" default:"[\"mark\",\"tom\",\"jack\"]"` +} + +func (c *Conf) Update(new config.Config) error { + newCfg, ok := new.(*Conf) + if !ok { + return errors.New("wrong configuration") + } + c.Name = newCfg.Name + c.Age = newCfg.Age + c.Friends = newCfg.Friends + c.LogLevel = newCfg.LogLevel + return nil +} diff --git a/example/server/configs.http b/example/server/configs.http index 7ec578c..d9ae6cc 100644 --- a/example/server/configs.http +++ b/example/server/configs.http @@ -7,9 +7,10 @@ PUT http://localhost:8080/configs/latest user-id: pippo { - "name": "gloria", - "age": 38, - "friends": ["joe", "mark"] + "name": "john", + "logLevel": "DEBUG", + "age": 40, + "friends": ["jack", "doug"] } ### List config versions diff --git a/example/server/main.go b/example/server/main.go index f7c7659..bbc69d8 100644 --- a/example/server/main.go +++ b/example/server/main.go @@ -13,28 +13,12 @@ import ( "time" config "github.com/rbroggi/streamingconfig" + appcfg "github.com/rbroggi/streamingconfig/example/config" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) -type conf struct { - Name string `json:"name" default:"john"` - Age int `json:"age"` - Friends []string `json:"friends" default:"[\"mark\",\"tom\",\"jack\"]"` -} - -func (c *conf) Update(new config.Config) error { - newCfg, ok := new.(*conf) - if !ok { - return errors.New("wrong configuration") - } - c.Name = newCfg.Name - c.Age = newCfg.Age - c.Friends = newCfg.Friends - return nil -} - func main() { port := os.Getenv("HTTP_PORT") if port == "" { @@ -75,10 +59,10 @@ func main() { <-done } -func initRepo(ctx context.Context) (*config.WatchedRepo[*conf], <-chan struct{}) { +func initRepo(ctx context.Context) (*config.WatchedRepo[*appcfg.Conf], <-chan struct{}) { lgr := slog.Default() db := getDb() - repo, err := config.NewWatchedRepo[*conf]( + repo, err := config.NewWatchedRepo[*appcfg.Conf]( config.Args{ Logger: lgr, DB: db, diff --git a/example/server/server.go b/example/server/server.go index 9c32d57..e346540 100644 --- a/example/server/server.go +++ b/example/server/server.go @@ -9,11 +9,12 @@ import ( "strconv" config "github.com/rbroggi/streamingconfig" + appcfg "github.com/rbroggi/streamingconfig/example/config" ) type server struct { lgr *slog.Logger - repo *config.WatchedRepo[*conf] + repo *config.WatchedRepo[*appcfg.Conf] } // latestConfigHandler returns the latest configuration @@ -50,7 +51,7 @@ func (s *server) putConfigHandler(w http.ResponseWriter, r *http.Request) { // Close the body to avoid leaks defer r.Body.Close() - cfg := new(conf) + cfg := new(appcfg.Conf) err = json.Unmarshal(body, cfg) if err != nil { s.lgr.With("error", err).ErrorContext(r.Context(), "unmarshalling request into configuration") @@ -59,7 +60,7 @@ func (s *server) putConfigHandler(w http.ResponseWriter, r *http.Request) { return } - updated, err := s.repo.UpdateConfig(r.Context(), config.UpdateConfigCmd[*conf]{ + updated, err := s.repo.UpdateConfig(r.Context(), config.UpdateConfigCmd[*appcfg.Conf]{ By: userID, Config: cfg, })