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

Commit 29a0ef5

Browse files
committed
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 8aff231 commit 29a0ef5

File tree

9 files changed

+168
-160
lines changed

9 files changed

+168
-160
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: 50 additions & 67 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"
@@ -27,95 +24,83 @@ import (
2724
"go.uber.org/zap"
2825
)
2926

30-
var build = "develop"
27+
const serviceName = "runner"
3128

3229
var serviceInfo = observability.ServiceInfo{
33-
Name: "runner",
34-
Version: build,
30+
Name: serviceName,
31+
Version: "0.1.2",
3532
}
3633

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

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

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

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

7681
func runCmd(cmd *cobra.Command, args []string) {
77-
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
82+
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
7883
defer cancel()
7984

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

8694
log := obs.Log()
8795

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

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

117102
// Database
118-
log.Info("startup", zap.String("status", "initializing database support"), zap.String("host", cfg.DB.Host))
103+
log.Info("Connecting to the database", zap.String("host", cfg.DB.Host))
119104
db, err := database.Open(database.Config{
120105
User: cfg.DB.User,
121106
Password: cfg.DB.Password,
@@ -128,8 +113,9 @@ func runCmd(cmd *cobra.Command, args []string) {
128113
if err != nil {
129114
log.Fatal("Unable to establish DB connection", zap.Error(err))
130115
}
116+
131117
defer func() {
132-
log.Info("closing database connection")
118+
log.Info("Closing the database connection")
133119
_ = db.Close()
134120
}()
135121

@@ -143,34 +129,31 @@ func runCmd(cmd *cobra.Command, args []string) {
143129
executorFactory := executor.NewFactory(&http.Client{Timeout: 30 * time.Second})
144130

145131
runner := runner.New(runner.Config{
146-
JobService: jobService,
147-
Metrics: metrics.NewRunnerMetrics(obsConfig.Metrics),
148-
Log: log,
149-
ExecutorFactory: executorFactory,
150-
InstanceId: cfg.ID,
151-
Interval: cfg.Interval,
152-
MaxConcurrentJobs: cfg.MaxConcurrentJobs,
153-
JobLockDuration: cfg.MaxJobLockTime,
132+
JobService: jobService,
133+
Metrics: metrics.NewRunnerMetrics(cfg.Observability.Metrics),
134+
Log: log,
135+
ExecutorFactory: executorFactory,
136+
InstanceId: cfg.ID,
137+
JobExecution: cfg.JobExecutionSettings,
154138
})
155139
runner.Start()
156140

157-
httpServer := devxHttp.NewServer(devxHttp.Configuration{Address: cfg.Web.APIHost}, obs)
141+
httpServer := devxHttp.NewServer(cfg.Http, obs)
158142
go func() {
159-
log.Info("Started HTTP server", zap.String("host", cfg.Web.APIHost))
143+
log.Info("Started HTTP server", zap.String("address", cfg.Http.Address))
160144
databaseCheck := database.NewHealthChecker(db)
161145
httpServer.Run(databaseCheck)
162146
}()
163147

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

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

172156
// stop the runner
173157
runner.Stop(ctx)
174-
log.Info("shutdown", zap.String("status", "shutdown complete"))
175158
}
176159
}

0 commit comments

Comments
 (0)