-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.go
More file actions
113 lines (99 loc) · 2.92 KB
/
Copy pathconfig.go
File metadata and controls
113 lines (99 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package config
import (
"fmt"
"os"
"strconv"
"time"
"github.com/google/uuid"
)
// Config holds process configuration from the environment. Values match INSTRUCTIONS.md (operational reference).
type Config struct {
CRDBDSN string
RedisAddr string
RedisKeyPrefix string
OrchestratorListen string
ReconcileInterval time.Duration
WorkerID string
WorkerConcurrency int
WorkerHeartbeatInterval time.Duration
LeaseDuration time.Duration
RetryBackoff time.Duration
// StaleRunningAfter is the minimum time a task may stay status=running before the
// reconciler considers reclaiming it when the Redis lease key is absent.
StaleRunningAfter time.Duration
}
// Load reads configuration from the environment. CRDB_DSN is required; other fields use documented defaults.
func Load() (Config, error) {
c := Config{
RedisAddr: getEnv("REDIS_ADDR", "127.0.0.1:6379"),
RedisKeyPrefix: getEnv("REDIS_KEY_PREFIX", "dto:"),
OrchestratorListen: getEnv("ORCHESTRATOR_LISTEN", ":8080"),
ReconcileInterval: 30 * time.Second,
LeaseDuration: 30 * time.Second,
RetryBackoff: 5 * time.Second,
WorkerConcurrency: 1,
WorkerHeartbeatInterval: 30 * time.Second,
}
if v := os.Getenv("CRDB_DSN"); v == "" {
return Config{}, fmt.Errorf("CRDB_DSN is required")
} else {
c.CRDBDSN = v
}
if v := os.Getenv("LEASE_DURATION"); v != "" {
d, err := time.ParseDuration(v)
if err != nil {
return Config{}, fmt.Errorf("LEASE_DURATION: %w", err)
}
c.LeaseDuration = d
}
if v := os.Getenv("RECONCILE_INTERVAL"); v != "" {
d, err := time.ParseDuration(v)
if err != nil {
return Config{}, fmt.Errorf("RECONCILE_INTERVAL: %w", err)
}
c.ReconcileInterval = d
}
if v := os.Getenv("RETRY_BACKOFF"); v != "" {
d, err := time.ParseDuration(v)
if err != nil {
return Config{}, fmt.Errorf("RETRY_BACKOFF: %w", err)
}
c.RetryBackoff = d
}
c.StaleRunningAfter = 2 * c.LeaseDuration
if v := os.Getenv("STALE_RUNNING_AFTER"); v != "" {
d, err := time.ParseDuration(v)
if err != nil {
return Config{}, fmt.Errorf("STALE_RUNNING_AFTER: %w", err)
}
c.StaleRunningAfter = d
}
if v := os.Getenv("WORKER_CONCURRENCY"); v != "" {
n, err := strconv.Atoi(v)
if err != nil || n < 1 {
return Config{}, fmt.Errorf("WORKER_CONCURRENCY must be a positive integer")
}
c.WorkerConcurrency = n
}
if v := os.Getenv("WORKER_HEARTBEAT_INTERVAL"); v != "" {
d, err := time.ParseDuration(v)
if err != nil {
return Config{}, fmt.Errorf("WORKER_HEARTBEAT_INTERVAL: %w", err)
}
if d < time.Second {
return Config{}, fmt.Errorf("WORKER_HEARTBEAT_INTERVAL must be at least 1s")
}
c.WorkerHeartbeatInterval = d
}
c.WorkerID = os.Getenv("WORKER_ID")
if c.WorkerID == "" {
c.WorkerID = uuid.New().String()
}
return c, nil
}
func getEnv(key, defaultVal string) string {
if v := os.Getenv(key); v != "" {
return v
}
return defaultVal
}