Skip to content

Commit 6b744fe

Browse files
Richard BaahRichard Baah
authored andcommitted
feat(config file): add config file for frequently changing values
1 parent abb0348 commit 6b744fe

21 files changed

+1520
-44
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package config
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"strings"
8+
9+
"gopkg.in/yaml.v3"
10+
)
11+
12+
var (
13+
kiloByte = 1024
14+
megaByte = 1024 * kiloByte
15+
gigaByte = 1024 * megaByte
16+
)
17+
18+
type Config struct {
19+
Server serverConfig `yaml:"server"`
20+
Batch batchConfig `yaml:"batch"`
21+
Query queryConfig `yaml:"query"`
22+
Metrics metricsConfig `yaml:"metrics"`
23+
}
24+
type serverConfig struct {
25+
Port int `yaml:"port"`
26+
Host string `yaml:"host"`
27+
Timeout int `yaml:"timeout"`
28+
MaxRequestSizeMB uint64 `yaml:"max_request_size_mb"` // max size of a file upload. passed in by grpc request
29+
}
30+
type batchConfig struct {
31+
Size int `yaml:"size"`
32+
EnableParallelRead bool `yaml:"enable_parallel_read"`
33+
MaxMemoryBeforeSpill uint64 `yaml:"max_memory_before_spill"`
34+
MaxFileSizeMB int `yaml:"max_file_size_mb"` // max size of a single file
35+
}
36+
type queryConfig struct {
37+
// should results be cached, server side? if so how long
38+
EnableCache bool `yaml:"enable_cache"`
39+
CacheTTLSeconds int `yaml:"cache_ttl_seconds"`
40+
// run queries concurrently? if so what the max before blocking
41+
EnableConcurrentExecution bool `yaml:"enable_concurrent_execution"`
42+
MaxConcurrentQueries int `yaml:"max_concurrent_queries"` // blocks after this many concurrent queries until one finishes
43+
}
44+
type metricsConfig struct {
45+
EnableMetrics bool `yaml:"enable_metrics"`
46+
MetricsPort int `yaml:"metrics_port"`
47+
MetricsHost string `yaml:"metrics_host"`
48+
ExportIntervalSecs int `yaml:"export_interval_secs"`
49+
// what queries have beeen sent
50+
EnableQueryStats bool `yaml:"enable_query_stats"`
51+
// memory usage over time
52+
EnableMemoryStats bool `yaml:"enable_memory_stats"`
53+
}
54+
55+
var configInstance *Config = &Config{
56+
Server: serverConfig{
57+
Port: 8080,
58+
Host: "localhost",
59+
Timeout: 30,
60+
MaxRequestSizeMB: 15,
61+
},
62+
Batch: batchConfig{
63+
Size: 1024 * 8, // rows per bathch
64+
EnableParallelRead: true,
65+
MaxMemoryBeforeSpill: uint64(gigaByte) * 2, // 2GB
66+
MaxFileSizeMB: 500, // 500MB
67+
},
68+
Query: queryConfig{
69+
EnableCache: true,
70+
CacheTTLSeconds: 600, // 10 minutes
71+
EnableConcurrentExecution: true,
72+
MaxConcurrentQueries: 2, // 2 concurrent queries
73+
},
74+
Metrics: metricsConfig{
75+
EnableMetrics: true,
76+
MetricsPort: 9999,
77+
MetricsHost: "localhost",
78+
ExportIntervalSecs: 60, // 1 minute
79+
EnableQueryStats: true,
80+
EnableMemoryStats: true,
81+
},
82+
}
83+
84+
func GetConfig() *Config {
85+
return configInstance
86+
}
87+
88+
// overwrite global instance with loaded config
89+
func Decode(filePath string) error {
90+
suffix := strings.Split(filePath, ".")[len(strings.Split(filePath, "."))-1]
91+
if suffix != "yaml" && suffix != "yml" {
92+
return errors.New("file must be a .yaml or .yml file")
93+
}
94+
r, err := os.Open(filePath)
95+
if err != nil {
96+
return err
97+
}
98+
config := make(map[string]interface{})
99+
decoder := yaml.NewDecoder(r)
100+
if err := decoder.Decode(config); err != nil {
101+
return fmt.Errorf("failed to decode config: %w", err)
102+
}
103+
mergeConfig(configInstance, config)
104+
return nil
105+
}
106+
func mergeConfig(dst *Config, src map[string]interface{}) {
107+
// =============================
108+
// SERVER
109+
// =============================
110+
if server, ok := src["server"].(map[string]interface{}); ok {
111+
if v, ok := server["port"].(int); ok {
112+
dst.Server.Port = v
113+
}
114+
if v, ok := server["host"].(string); ok {
115+
dst.Server.Host = v
116+
}
117+
if v, ok := server["timeout"].(int); ok {
118+
dst.Server.Timeout = v
119+
}
120+
if v, ok := server["max_request_size_mb"].(int); ok {
121+
dst.Server.MaxRequestSizeMB = uint64(v)
122+
}
123+
}
124+
125+
// =============================
126+
// BATCH
127+
// =============================
128+
if batch, ok := src["batch"].(map[string]interface{}); ok {
129+
if v, ok := batch["size"].(int); ok {
130+
dst.Batch.Size = v
131+
}
132+
if v, ok := batch["enable_parallel_read"].(bool); ok {
133+
dst.Batch.EnableParallelRead = v
134+
}
135+
if v, ok := batch["max_memory_before_spill"].(int); ok {
136+
dst.Batch.MaxMemoryBeforeSpill = uint64(v)
137+
}
138+
if v, ok := batch["max_file_size_mb"].(int); ok {
139+
dst.Batch.MaxFileSizeMB = v
140+
}
141+
}
142+
143+
// =============================
144+
// QUERY
145+
// =============================
146+
if query, ok := src["query"].(map[string]interface{}); ok {
147+
if v, ok := query["enable_cache"].(bool); ok {
148+
dst.Query.EnableCache = v
149+
}
150+
if v, ok := query["cache_ttl_seconds"].(int); ok {
151+
dst.Query.CacheTTLSeconds = v
152+
}
153+
if v, ok := query["enable_concurrent_execution"].(bool); ok {
154+
dst.Query.EnableConcurrentExecution = v
155+
}
156+
if v, ok := query["max_concurrent_queries"].(int); ok {
157+
dst.Query.MaxConcurrentQueries = v
158+
}
159+
}
160+
161+
// =============================
162+
// METRICS
163+
// =============================
164+
if metrics, ok := src["metrics"].(map[string]interface{}); ok {
165+
if v, ok := metrics["enable_metrics"].(bool); ok {
166+
dst.Metrics.EnableMetrics = v
167+
}
168+
if v, ok := metrics["metrics_port"].(int); ok {
169+
dst.Metrics.MetricsPort = v
170+
}
171+
if v, ok := metrics["metrics_host"].(string); ok {
172+
dst.Metrics.MetricsHost = v
173+
}
174+
if v, ok := metrics["export_interval_secs"].(int); ok {
175+
dst.Metrics.ExportIntervalSecs = v
176+
}
177+
if v, ok := metrics["enable_query_stats"].(bool); ok {
178+
dst.Metrics.EnableQueryStats = v
179+
}
180+
if v, ok := metrics["enable_memory_stats"].(bool); ok {
181+
dst.Metrics.EnableMemoryStats = v
182+
}
183+
}
184+
}

0 commit comments

Comments
 (0)