start.go RawHistoryFolder
1package cmd
2
3import (
4 "context"
5 "os"
6 "os/signal"
7 "sync"
8 "syscall"
9 "time"
10
11 "github.com/fsnotify/fsnotify"
12 "github.com/google/uuid"
13 "github.com/rs/zerolog"
14 "github.com/rs/zerolog/log"
15 "github.com/spf13/cobra"
16 "github.com/spf13/viper"
17 "gordon/internal/config"
18 "gordon/internal/container"
19 "gordon/internal/events"
20 "gordon/internal/proxy"
21 "gordon/internal/registry"
22)
23
24var startCmd = &cobra.Command{
25 Use: "start",
26 Short: "Start the Gordon server",
27 Long: `Start the container registry and reverse proxy server`,
28 Run: runStart,
29}
30
31func init() {
32 rootCmd.AddCommand(startCmd)
33}
34
35func runStart(cmd *cobra.Command, args []string) {
36 // Configure zerolog
37 zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
38 log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
39
40 cfg, err := config.Load()
41 if err != nil {
42 log.Fatal().Err(err).Msg("Failed to load config")
43 }
44
45 log.Info().Msg("Starting Gordon server...")
46 log.Info().Int("registry_port", cfg.Server.RegistryPort).Msg("Registry server")
47 log.Info().Int("proxy_port", cfg.Server.Port).Msg("Proxy server")
48 log.Info().Str("runtime", cfg.Server.Runtime).Msg("Container runtime")
49
50 // Initialize event bus
51 eventBus := events.NewInMemoryEventBus(100)
52 if err := eventBus.Start(); err != nil {
53 log.Fatal().Err(err).Msg("Failed to start event bus")
54 }
55
56 // Initialize container manager
57 manager, err := container.NewManager(cfg)
58 if err != nil {
59 log.Fatal().Err(err).Msg("Failed to initialize container manager")
60 }
61
62 // Create and subscribe container event handler
63 containerHandler := events.NewContainerEventHandler(manager, cfg)
64 if err := eventBus.Subscribe(containerHandler); err != nil {
65 log.Fatal().Err(err).Msg("Failed to subscribe container event handler")
66 }
67
68 // Setup config file watching for live reload
69 viper.WatchConfig()
70 viper.OnConfigChange(func(e fsnotify.Event) {
71 log.Info().
72 Str("file", e.Name).
73 Str("op", e.Op.String()).
74 Msg("Configuration file changed, reloading...")
75
76 // Reload configuration
77 newCfg, err := config.Load()
78 if err != nil {
79 log.Error().Err(err).Msg("Failed to reload configuration")
80 return
81 }
82
83 // Update the configuration reference
84 cfg = newCfg
85
86 // Update container handler config
87 containerHandler = events.NewContainerEventHandler(manager, cfg)
88 if err := eventBus.Subscribe(containerHandler); err != nil {
89 log.Error().Err(err).Msg("Failed to re-subscribe container event handler")
90 return
91 }
92
93 // Publish config reload event
94 configReloadEvent := events.Event{
95 ID: uuid.New().String(),
96 Type: events.ConfigReload,
97 Timestamp: time.Now(),
98 }
99
100 if err := eventBus.Publish(configReloadEvent); err != nil {
101 log.Error().Err(err).Msg("Failed to publish config reload event")
102 } else {
103 log.Info().Msg("Configuration reloaded successfully")
104 }
105 })
106
107 // Sync existing containers
108 ctx, cancel := context.WithCancel(context.Background())
109 if err := manager.SyncContainers(ctx); err != nil {
110 log.Warn().Err(err).Msg("Failed to sync existing containers")
111 }
112
113 var wg sync.WaitGroup
114
115 // Start registry server
116 registryServer, err := registry.NewServer(cfg, eventBus)
117 if err != nil {
118 log.Fatal().Err(err).Msg("Failed to initialize registry server")
119 }
120 wg.Add(1)
121 go func() {
122 defer wg.Done()
123 if err := registryServer.Start(ctx); err != nil {
124 log.Error().Err(err).Msg("Registry server error")
125 }
126 }()
127
128 // Start proxy server
129 proxyServer := proxy.NewServer(cfg, manager)
130 wg.Add(1)
131 go func() {
132 defer wg.Done()
133 if err := proxyServer.Start(ctx); err != nil {
134 log.Error().Err(err).Msg("Proxy server error")
135 }
136 }()
137
138 // Wait for interrupt signal
139 sigChan := make(chan os.Signal, 1)
140 signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
141 <-sigChan
142
143 log.Info().Msg("Shutting down servers...")
144 cancel()
145
146 // Stop event bus
147 if err := eventBus.Stop(); err != nil {
148 log.Error().Err(err).Msg("Failed to stop event bus")
149 }
150
151 // Give servers time to shutdown gracefully
152 done := make(chan struct{})
153 go func() {
154 wg.Wait()
155 close(done)
156 }()
157
158 select {
159 case <-done:
160 log.Info().Msg("Servers stopped gracefully")
161 case <-time.After(10 * time.Second):
162 log.Warn().Msg("Force shutdown after timeout")
163 }
164}