()
| 221 | } |
| 222 | |
| 223 | func (sm *ServiceManager) Shutdown() { |
| 224 | log.Println("Stopping all services...") |
| 225 | |
| 226 | sigChan := make(chan os.Signal, 1) |
| 227 | signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) |
| 228 | |
| 229 | var forceKillOnce sync.Once |
| 230 | |
| 231 | forceKill := make(chan struct{}) |
| 232 | |
| 233 | var wg sync.WaitGroup |
| 234 | |
| 235 | for name := range sm.Services { |
| 236 | wg.Add(1) |
| 237 | go func(serviceName string) { |
| 238 | defer wg.Done() |
| 239 | |
| 240 | if err := sm.StopService(serviceName); err != nil { |
| 241 | if !strings.Contains(err.Error(), "not working") { |
| 242 | log.Printf("%s error while stopping: %v", serviceName, err) |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | sm.Mu.RLock() |
| 247 | service, exists := sm.Services[serviceName] |
| 248 | sm.Mu.RUnlock() |
| 249 | |
| 250 | if exists && service.CMD != nil && service.CMD.Process != nil { |
| 251 | if err := service.CMD.Process.Signal(syscall.Signal(0)); err == nil { |
| 252 | log.Printf("Service still working, forcing to stop: %s", serviceName) |
| 253 | KillProcess(service.PID) |
| 254 | } |
| 255 | } |
| 256 | }(name) |
| 257 | } |
| 258 | |
| 259 | go func() { |
| 260 | select { |
| 261 | case <-sigChan: |
| 262 | log.Println("Force shutdown requested by user (CTRL+C again)") |
| 263 | forceKillOnce.Do(func() { |
| 264 | close(forceKill) |
| 265 | }) |
| 266 | case <-forceKill: |
| 267 | return |
| 268 | } |
| 269 | }() |
| 270 | |
| 271 | done := make(chan struct{}) |
| 272 | go func() { |
| 273 | wg.Wait() |
| 274 | close(done) |
| 275 | }() |
| 276 | |
| 277 | select { |
| 278 | case <-done: |
| 279 | log.Println("All services were stopped successfully!") |
| 280 | case <-time.After(30 * time.Second): |
no test coverage detected