From 8b087b50216f40ae1ee80b37a12a662b263604d9 Mon Sep 17 00:00:00 2001 From: gjahn <gregor.jahn@bht-berlin.de> Date: Sat, 25 Nov 2023 00:21:16 +0100 Subject: [PATCH] Add Redis as backing service to persist state --- configuration/config.go | 6 +++ go.mod | 3 ++ go.sum | 6 +++ main.go | 7 ++- state/persistent.go | 109 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 state/persistent.go diff --git a/configuration/config.go b/configuration/config.go index 83dc351..22d9fcf 100644 --- a/configuration/config.go +++ b/configuration/config.go @@ -12,6 +12,12 @@ type Config struct { Environment string `env:"ENV_NAME" envDefault:"development"` Host string `env:"HOST" envDefault:"127.0.0.1"` Port int16 `env:"PORT" envDefault:"3000"` + + DatabaseHost string `env:"DB_HOST" envDefault:""` + DatabasePort int16 `env:"DB_PORT" envDefault:"6379"` + DatabaseName int `env:"DB_NAME" envDefault:"0"` + DatabaseUsername string `env:"DB_USERNAME" envDefault:""` + DatabasePassword string `env:"DB_PASSWORD" envDefault:""` } diff --git a/go.mod b/go.mod index 83356a2..3e4f764 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,15 @@ require ( github.com/caarlos0/env/v9 v9.0.0 github.com/go-playground/validator/v10 v10.15.5 github.com/gofiber/fiber/v2 v2.49.2 + github.com/redis/go-redis/v9 v9.3.0 github.com/stretchr/testify v1.8.4 ) require ( github.com/andybalholm/brotli v1.0.5 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect diff --git a/go.sum b/go.sum index 91ab0de..e1c0817 100644 --- a/go.sum +++ b/go.sum @@ -2,9 +2,13 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/ github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc= github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= @@ -25,6 +29,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0= +github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/main.go b/main.go index c7866eb..cacfd73 100644 --- a/main.go +++ b/main.go @@ -28,7 +28,12 @@ func main() { DisableStartupMessage: config.Environment != "development", }) - store := state.NewEphemeralStore() + var store state.Store + if len( config.DatabaseHost ) <= 0 { + store = state.NewEphemeralStore() + } else { + store = state.NewPersistentStore( config ) + } var isHealthy = false diff --git a/state/persistent.go b/state/persistent.go new file mode 100644 index 0000000..ae23264 --- /dev/null +++ b/state/persistent.go @@ -0,0 +1,109 @@ +package state + +import ( + "fmt" + "runtime" + "context" + "time" + + "webservice/configuration" + + db "github.com/redis/go-redis/v9" +) + + + +type Persistent struct { + client *db.Client + ctx context.Context + timeout time.Duration +} + + +func NewPersistentStore( c *configuration.Config ) *Persistent { + return &Persistent{ + client: db.NewClient( &db.Options{ + Addr: fmt.Sprintf( "%s:%d", c.DatabaseHost, c.DatabasePort ), + Username: c.DatabaseUsername, + Password: c.DatabasePassword, + DB: c.DatabaseName, + + DialTimeout: time.Second * 3, + ContextTimeoutEnabled: true, + + MaxRetries: 3, + MinRetryBackoff: time.Second * 1, + MaxRetryBackoff: time.Second * 2, + + PoolSize: 10 * runtime.NumCPU(), + MaxActiveConns: 10 * runtime.NumCPU(), + }), + + timeout: time.Second * 20, + } +} + + +func ( e *Persistent ) Add( i *Item ) error { + ctx, cancel := context.WithTimeout( context.TODO(), e.timeout ) + defer cancel() + + name := i.Name() + if err := e.client.HSet( + ctx, name, + "data", i.Data(), + "mime", i.MimeType(), + ).Err(); err != nil { + return err + } + return nil +} + + +func ( e *Persistent ) Remove( name string ) error { + ctx, cancel := context.WithTimeout( context.TODO(), e.timeout ) + defer cancel() + + if err := e.client.Del( ctx, name ).Err(); err != nil { + return err + } + return nil +} + + +func ( e *Persistent ) Fetch( name string ) ( *Item, error ) { + ctx, cancel := context.WithTimeout( context.TODO(), e.timeout ) + defer cancel() + + value, err := e.client.HGetAll( ctx, name ).Result() + if err != nil { + return nil, err + } + + var item *Item = nil + if len( value ) >= 1 { + item = NewItem( name, value[ "mime" ], []byte( value[ "data" ] ) ) + } + return item, nil +} + + +func ( e *Persistent ) Show() ( []string, error ) { + ctx, cancel := context.WithTimeout( context.TODO(), e.timeout ) + defer cancel() + + var names []string + i := e.client.Scan( ctx, 0, "", 0 ).Iterator() + for i.Next( ctx ){ + names = append( names, i.Val() ) + } + if err := i.Err(); err != nil { + return nil, err + } + return names, nil +} + + +func ( e *Persistent ) Disconnect() error { + return e.client.Close() +} \ No newline at end of file -- GitLab