Skip to content
This repository was archived by the owner on Feb 15, 2025. It is now read-only.

Commit e181507

Browse files
authored
Reworked config with Viper (#18)
* Ported config into Viper - also optimized the code a bit. * Linter issue fix * Renamed struct fields for viper usage, added flag with config * Added config files for runner and manager
1 parent 9184c9c commit e181507

File tree

9 files changed

+167
-159
lines changed

9 files changed

+167
-159
lines changed

cmd/manager/main.go

Lines changed: 43 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@ package main
22

33
import (
44
"context"
5-
"errors"
6-
"fmt"
75
"os/signal"
86
"syscall"
9-
"time"
107

118
"github.com/GLCharge/otelzap"
12-
"github.com/ardanlabs/conf/v3"
139
"github.com/spf13/cobra"
1410
"github.com/spf13/viper"
1511
devxCfg "github.com/xBlaz3kx/DevX/configuration"
@@ -23,96 +19,81 @@ import (
2319
"go.uber.org/zap"
2420
)
2521

26-
var build = "develop"
22+
const serviceName = "manager"
2723

2824
var serviceInfo = observability.ServiceInfo{
29-
Name: "manager",
30-
Version: build,
25+
Name: serviceName,
26+
Version: "0.1.2",
3127
}
3228

29+
var configFilePath string
30+
3331
type config struct {
34-
conf.Version
35-
Web struct {
36-
ReadTimeout time.Duration `conf:"default:5s"`
37-
WriteTimeout time.Duration `conf:"default:10s"`
38-
IdleTimeout time.Duration `conf:"default:120s"`
39-
ShutdownTimeout time.Duration `conf:"default:20s"`
40-
APIHost string `conf:"default:0.0.0.0:8000"`
41-
}
42-
DB database.Config
43-
OpenAPI struct {
44-
Scheme string `conf:"default:http"`
45-
Enable bool `conf:"default:true"`
46-
Host string `conf:"default:localhost:8000"`
47-
}
32+
Observability observability.Config `mapstructure:"observability" yaml:"observability" json:"observability"`
33+
Http devxHttp.Configuration `mapstructure:"http" yaml:"http" json:"http"`
34+
DB database.Config `mapstructure:"db" yaml:"db" json:"db"`
35+
OpenAPI struct {
36+
Scheme string `conf:"default:http" json:"scheme,omitempty"`
37+
Enable bool `conf:"default:true" json:"enable,omitempty"`
38+
Host string `conf:"default:localhost:8000" json:"host,omitempty"`
39+
} `json:"openAPI"`
4840
}
4941

5042
var rootCmd = &cobra.Command{
5143
Use: "scheduler",
5244
Short: "Scheduler manager",
53-
PreRun: func(cmd *cobra.Command, args []string) {
45+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
46+
devxCfg.SetDefaults(serviceName)
47+
devxCfg.SetupEnv(serviceName)
48+
5449
viper.SetDefault("storage.encryption.key", "ishouldreallybechanged")
50+
viper.SetDefault("db.disable_tls", true)
51+
viper.SetDefault("db.max_open_conns", 1)
52+
viper.SetDefault("db.max_idle_conns", 10)
53+
viper.SetDefault("observability.logging.level", observability.LogLevelInfo)
54+
5555
devxCfg.InitConfig("", "./config", ".")
5656

5757
postgres.SetEncryptor(security.NewEncryptorFromEnv())
5858
},
5959
Run: runCmd,
6060
}
6161

62+
func init() {
63+
rootCmd.PersistentFlags().StringVar(&configFilePath, "config", "", "config file (default is $HOME/.config/runner.yaml)")
64+
_ = viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
65+
}
66+
6267
func main() {
63-
cobra.OnInitialize(func() {
64-
logger.SetupLogging()
65-
devxCfg.SetupEnv("manager")
66-
})
68+
cobra.OnInitialize(logger.SetupLogging)
6769
err := rootCmd.Execute()
6870
if err != nil {
6971
panic(err)
7072
}
7173
}
7274

7375
func runCmd(cmd *cobra.Command, args []string) {
74-
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
76+
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
7577
defer cancel()
7678

77-
obsConfig := observability.Config{}
78-
obs, err := observability.NewObservability(ctx, serviceInfo, obsConfig)
79+
// Configuration
80+
cfg := &config{}
81+
devxCfg.GetConfiguration(viper.GetViper(), cfg)
82+
83+
// Setup observability
84+
obs, err := observability.NewObservability(ctx, serviceInfo, cfg.Observability)
7985
if err != nil {
8086
otelzap.L().Fatal("failed to initialize observability", zap.Error(err))
8187
}
8288

8389
log := obs.Log()
8490

85-
// Configuration
86-
cfg := config{
87-
Version: conf.Version{
88-
Build: build,
89-
Desc: "copyright information here",
90-
},
91-
}
92-
93-
const prefix = "MANAGER"
94-
help, err := conf.Parse(prefix, &cfg)
95-
if err != nil {
96-
if errors.Is(err, conf.ErrHelpWanted) {
97-
fmt.Println(help)
98-
return
99-
}
100-
return
101-
}
102-
10391
// App Starting
104-
log.Info("starting service", zap.String("version", build))
92+
log.Info("Starting the manager", zap.String("version", serviceInfo.Version), zap.Any("config", cfg))
10593
defer log.Info("shutdown complete")
10694

107-
out, err := conf.String(&cfg)
108-
if err != nil {
109-
return
110-
}
111-
112-
log.Info("startup", zap.String("config", out))
113-
11495
// Database Support
115-
log.Info("startup", zap.String("status", "initializing database support"), zap.String("host", cfg.DB.Host))
96+
log.Info("Connecting to the database", zap.String("host", cfg.DB.Host))
11697
db, err := database.Open(database.Config{
11798
User: cfg.DB.User,
11899
Password: cfg.DB.Password,
@@ -123,17 +104,15 @@ func runCmd(cmd *cobra.Command, args []string) {
123104
DisableTLS: cfg.DB.DisableTLS,
124105
})
125106
if err != nil {
126-
return
107+
log.Fatal("failed to connect to the database", zap.Error(err))
127108
}
128109

129110
defer func() {
130-
log.Info("shutdown", zap.String("status", "stopping database support"), zap.String("host", cfg.DB.Host))
111+
log.Info("Closing the database connection")
131112
_ = db.Close()
132113
}()
133114

134-
httpCfg := devxHttp.Configuration{Address: cfg.Web.APIHost}
135-
httpServer := devxHttp.NewServer(httpCfg, obs)
136-
115+
httpServer := devxHttp.NewServer(cfg.Http, obs)
137116
api.Api(httpServer.Router(), api.APIMuxConfig{
138117
Log: log,
139118
DB: db,
@@ -145,18 +124,12 @@ func runCmd(cmd *cobra.Command, args []string) {
145124
})
146125

147126
go func() {
148-
log.Info("Starting HTTP server", zap.String("host", httpCfg.Address))
127+
log.Info("Starting HTTP server", zap.String("host", cfg.Http.Address))
149128
databaseCheck := database.NewHealthChecker(db)
150129
httpServer.Run(databaseCheck)
151130
}()
152131

153-
// Start API Service
154-
log.Info("startup", zap.String("status", "initializing Management API support"))
155-
156132
// Shutdown
157-
select {
158-
case sig := <-ctx.Done():
159-
log.Info("shutdown", zap.String("status", "shutdown started"), zap.Any("signal", sig))
160-
defer log.Info("shutdown", zap.String("status", "shutdown complete"), zap.Any("signal", sig))
161-
}
133+
<-ctx.Done()
134+
log.Info("Shutting down the manager")
162135
}

cmd/runner/main.go

Lines changed: 49 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,12 @@ package main
22

33
import (
44
"context"
5-
"errors"
6-
"fmt"
75
"net/http"
86
"os/signal"
97
"syscall"
108
"time"
119

1210
"github.com/GLCharge/otelzap"
13-
"github.com/ardanlabs/conf/v3"
1411
"github.com/spf13/cobra"
1512
"github.com/spf13/viper"
1613
devxCfg "github.com/xBlaz3kx/DevX/configuration"
@@ -26,95 +23,83 @@ import (
2623
"go.uber.org/zap"
2724
)
2825

29-
var build = "develop"
26+
const serviceName = "runner"
3027

3128
var serviceInfo = observability.ServiceInfo{
32-
Name: "runner",
33-
Version: build,
29+
Name: serviceName,
30+
Version: "0.1.2",
3431
}
3532

33+
var configFilePath string
34+
3635
type config struct {
37-
conf.Version
38-
Web struct {
39-
ReadTimeout time.Duration `conf:"default:5s"`
40-
WriteTimeout time.Duration `conf:"default:10s"`
41-
IdleTimeout time.Duration `conf:"default:120s"`
42-
ShutdownTimeout time.Duration `conf:"default:20s"`
43-
APIHost string `conf:"default:0.0.0.0:8000"`
44-
}
45-
DB database.Config
46-
ID string `conf:"default:instance1"`
47-
Interval time.Duration `conf:"default:10s"`
48-
MaxConcurrentJobs int `conf:"default:100"`
49-
MaxJobLockTime time.Duration `conf:"default:1m"`
36+
Observability observability.Config `mapstructure:"observability" yaml:"observability" json:"observability"`
37+
Http devxHttp.Configuration `mapstructure:"http" yaml:"http" json:"http"`
38+
DB database.Config `mapstructure:"db" yaml:"db" json:"db"`
39+
ID string `mapstructure:"id" yaml:"id" json:"id,omitempty"`
40+
JobExecutionSettings runner.JobExecutionSettings `mapstructure:"jobExecutionSettings" yaml:"jobExecutionSettings" json:"jobExecutionSettings"`
5041
}
5142

5243
var rootCmd = &cobra.Command{
5344
Use: "runner",
5445
Short: "Scheduler runner",
55-
PreRun: func(cmd *cobra.Command, args []string) {
46+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
47+
devxCfg.SetDefaults(serviceName)
48+
devxCfg.SetupEnv(serviceName)
49+
5650
viper.SetDefault("storage.encryption.key", "ishouldreallybechanged")
57-
devxCfg.InitConfig("", "./config", ".")
51+
viper.SetDefault("db.disableTls", true)
52+
viper.SetDefault("db.maxOpenConns", 1)
53+
viper.SetDefault("db.maxIdleConns", 10)
54+
viper.SetDefault("observability.logging.level", observability.LogLevelInfo)
55+
56+
viper.SetDefault("jobExecutionSettings.maxConcurrentJobs", 100)
57+
viper.SetDefault("jobExecutionSettings.interval", time.Second*10)
58+
viper.SetDefault("jobExecutionSettings.maxJobLockTime", time.Minute)
59+
60+
devxCfg.InitConfig(configFilePath, "./config", ".")
5861

5962
postgres.SetEncryptor(security.NewEncryptorFromEnv())
6063
},
6164
Run: runCmd,
6265
}
6366

67+
func init() {
68+
rootCmd.PersistentFlags().StringVar(&configFilePath, "config", "", "config file (default is $HOME/.config/runner.yaml)")
69+
_ = viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config"))
70+
}
71+
6472
func main() {
65-
cobra.OnInitialize(func() {
66-
logger.SetupLogging()
67-
devxCfg.SetupEnv("runner")
68-
})
73+
cobra.OnInitialize(logger.SetupLogging)
6974
err := rootCmd.Execute()
7075
if err != nil {
7176
panic(err)
7277
}
7378
}
7479

7580
func runCmd(cmd *cobra.Command, args []string) {
76-
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
81+
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
7782
defer cancel()
7883

79-
obsConfig := observability.Config{}
80-
obs, err := observability.NewObservability(ctx, serviceInfo, obsConfig)
84+
// Read the configuration
85+
cfg := &config{}
86+
devxCfg.GetConfiguration(viper.GetViper(), cfg)
87+
88+
obs, err := observability.NewObservability(ctx, serviceInfo, cfg.Observability)
8189
if err != nil {
8290
otelzap.L().Fatal("failed to initialize observability", zap.Error(err))
8391
}
8492

8593
log := obs.Log()
8694

87-
// config
88-
cfg := config{
89-
Version: conf.Version{
90-
Build: build,
91-
Desc: "copyright information here",
92-
},
93-
}
94-
95-
const prefix = "RUNNER"
96-
help, err := conf.Parse(prefix, &cfg)
97-
if err != nil {
98-
if errors.Is(err, conf.ErrHelpWanted) {
99-
fmt.Println(help)
100-
return
101-
}
102-
return
103-
}
104-
10595
// App Starting
106-
log.Info("starting service", zap.String("version", build))
96+
log.Info("Starting the runner", zap.String("version", serviceInfo.Version))
10797
defer log.Info("shutdown complete")
10898

109-
out, err := conf.String(&cfg)
110-
if err != nil {
111-
log.Fatal("parsing config", zap.Error(err))
112-
}
113-
114-
log.Info("Using config", zap.Any("config", out))
99+
log.Info("Using config", zap.Any("config", cfg))
115100

116101
// Database
117-
log.Info("startup", zap.String("status", "initializing database support"), zap.String("host", cfg.DB.Host))
102+
log.Info("Connecting to the database", zap.String("host", cfg.DB.Host))
118103
db, err := database.Open(database.Config{
119104
User: cfg.DB.User,
120105
Password: cfg.DB.Password,
@@ -127,8 +112,9 @@ func runCmd(cmd *cobra.Command, args []string) {
127112
if err != nil {
128113
log.Fatal("Unable to establish DB connection", zap.Error(err))
129114
}
115+
130116
defer func() {
131-
log.Info("closing database connection")
117+
log.Info("Closing the database connection")
132118
_ = db.Close()
133119
}()
134120

@@ -142,33 +128,30 @@ func runCmd(cmd *cobra.Command, args []string) {
142128
executorFactory := executor.NewFactory(&http.Client{Timeout: 30 * time.Second})
143129

144130
runner := runner.New(runner.Config{
145-
JobService: jobService,
146-
Log: log,
147-
ExecutorFactory: executorFactory,
148-
InstanceId: cfg.ID,
149-
Interval: cfg.Interval,
150-
MaxConcurrentJobs: cfg.MaxConcurrentJobs,
151-
JobLockDuration: cfg.MaxJobLockTime,
131+
JobService: jobService,
132+
Log: log,
133+
ExecutorFactory: executorFactory,
134+
InstanceId: cfg.ID,
135+
JobExecution: cfg.JobExecutionSettings,
152136
})
153137
runner.Start()
154138

155-
httpServer := devxHttp.NewServer(devxHttp.Configuration{Address: cfg.Web.APIHost}, observability.NewNoopObservability())
139+
httpServer := devxHttp.NewServer(cfg.Http, observability.NewNoopObservability())
156140
go func() {
157-
log.Info("Started HTTP server", zap.String("host", cfg.Web.APIHost))
141+
log.Info("Started HTTP server", zap.String("address", cfg.Http.Address))
158142
databaseCheck := database.NewHealthChecker(db)
159143
httpServer.Run(databaseCheck)
160144
}()
161145

162146
//nolint:all
163147
select {
164148
case _ = <-ctx.Done():
165-
log.Info("shutdown", zap.String("status", "shutdown started"))
149+
log.Info("Shutting down the runner")
166150

167151
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
168152
defer cancel()
169153

170154
// stop the runner
171155
runner.Stop(ctx)
172-
log.Info("shutdown", zap.String("status", "shutdown complete"))
173156
}
174157
}

0 commit comments

Comments
 (0)