/
config-supervisor.go
134 lines (114 loc) · 3.49 KB
/
config-supervisor.go
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package main
import (
"fmt"
"log"
"os"
"os/signal"
"runtime"
"runtime/pprof"
"time"
"github.com/adobe-apiplatform/api-gateway-config-supervisor/sync"
"github.com/adobe-apiplatform/api-gateway-config-supervisor/ws"
_ "net/http/pprof"
"github.com/carlescere/scheduler"
"github.com/spf13/pflag"
"github.com/koyachi/go-term-ansicolor/ansicolor"
)
var (
// Flags
cpuprofile = pflag.StringP("cpuprofile", "", "", "Write cpu profile to file")
version = pflag.BoolP("version", "V", false, "Print the version number")
syncInterval = pflag.DurationP("sync-interval", "", time.Second*5, "Time interval for the next sync")
syncCmd = pflag.StringP("sync-cmd", "", "echo sync-cmd not defined", "Command used to syncing")
syncFolder = pflag.StringP("sync-folder", "", "~/tmp/api-gateway-config", "The folder to watch for changes.")
reloadCmd = pflag.StringP("reload-cmd", "", "echo reload-cmd not defined", "Command used to reload the gateway")
httpAddr = pflag.StringP("http-addr", "", "127.0.0.1:8888", "Http Address exposing a /health-check for the sync process")
debug = pflag.BoolP("debug", "v", false, "Print extra debug information")
status = sync.GetStatusInstance()
)
func syntaxError() {
fmt.Fprintf(os.Stderr, `Execute a sync command and watch a folder for changes.`)
}
// ParseFlags parses the command line flags
func ParseFlags() {
pflag.Usage = syntaxError
pflag.Parse()
runtime.GOMAXPROCS(runtime.NumCPU())
// Setup profiling if desired
if *cpuprofile != "" {
log.Println(ansicolor.Red("Starting CPU Profiling"))
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
defer f.Close()
err = pprof.StartCPUProfile(f)
if err != nil {
log.Fatal(err)
}
defer pprof.StopCPUProfile()
}
}
func executeSyncCmd() {
go sync.Execute(*syncCmd)
status.LastSync = time.Now()
}
func executeReloadCmd() {
log.Println(ansicolor.Red("Executing Reload Cmd"))
go sync.Execute(*reloadCmd)
status.LastReload = time.Now()
}
func checkForReload() {
if time.Since(status.LastFSChangeDetected) < time.Since(status.LastReload) && time.Since(status.LastReload) > *syncInterval {
status.LastReload = time.Now()
executeReloadCmd()
}
}
//watches for changes in the syncFolder, execute reloadCmd when there are changes
func watchForFSChanges() {
c := sync.WatchFolderRecursive(*syncFolder, *debug)
for {
select {
case file := <-c:
if file == "" {
continue
}
status.LastFSChangeDetected = time.Now()
if time.Since(status.LastReload) > *syncInterval {
status.LastReload = time.Now()
go func() {
// wait a little in case there are more changes to sync
for time.Since(status.LastFSChangeDetected) < time.Second*1 {
time.Sleep(1 * time.Second)
}
executeReloadCmd()
}()
}
}
}
}
func startWebServer() {
go ws.RunWS(*httpAddr)
}
func startWatchingFS() {
go watchForFSChanges()
scheduler.Every(int(syncInterval.Seconds())).Seconds().Run(executeSyncCmd)
scheduler.Every(int(syncInterval.Seconds())).Seconds().Run(checkForReload)
}
func waitToTerminate() {
// Waiting for terminating (i use a sighandler like in vitess)
terminate := make(chan os.Signal)
signal.Notify(terminate, os.Interrupt)
<-terminate
}
func main() {
ParseFlags()
if *version {
fmt.Printf("config-supervisor %s\n", "0.1")
os.Exit(0)
}
startWebServer() // expose a /health-check API on the localhost
startWatchingFS() // watch for file system changes
waitToTerminate() // wait until the program terminates
log.Printf("Stopped ... ")
}