func (runner *Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error { close(ready) if runner.noop { <-signals return nil } runner.logger.Info("start") defer runner.logger.Info("done") ticker := time.NewTicker(runner.syncInterval) scannersGroup := grouper.NewDynamic(nil, 0, 0) scannersClient := scannersGroup.Client() exits := scannersClient.ExitListener() insertScanner := scannersClient.Inserter() scanners := ifrit.Invoke(scannersGroup) scanning := make(map[string]bool) scanningResourceTypes := make(map[string]bool) runner.tick(scanning, scanningResourceTypes, insertScanner) dance: for { select { case <-signals: scanners.Signal(os.Interrupt) // don't bother waiting for scanners on shutdown break dance case exited := <-exits: if exited.Err != nil { runner.logger.Error("scanner-failed", exited.Err, lager.Data{ "member": exited.Member.Name, }) } else { runner.logger.Info("scanner-exited", lager.Data{ "member": exited.Member.Name, }) } delete(scanning, exited.Member.Name) case <-ticker.C: runner.tick(scanning, scanningResourceTypes, insertScanner) } } return nil }
}) AfterEach(func() { childRunner1.EnsureExit() childRunner2.EnsureExit() childRunner3.EnsureExit() }) Describe("Get", func() { var member1, member2, member3 grouper.Member BeforeEach(func() { member1 = grouper.Member{"child1", childRunner1} member2 = grouper.Member{"child2", childRunner2} member3 = grouper.Member{"child3", childRunner3} pool = grouper.NewDynamic(nil, 3, 2) client = pool.Client() poolProcess = ifrit.Envoke(pool) insert := client.Inserter() Eventually(insert).Should(BeSent(member1)) Eventually(insert).Should(BeSent(member2)) Eventually(insert).Should(BeSent(member3)) }) It("returns a process when the member is present", func() { signal1 := childRunner1.WaitForCall() p, ok := client.Get("child1") Ω(ok).Should(BeTrue()) p.Signal(syscall.SIGUSR2) Eventually(signal1).Should(Receive(Equal(syscall.SIGUSR2)))
func main() { rootConfig, err := config.NewConfig(os.Args) logger := rootConfig.Logger err = rootConfig.Validate() if err != nil { logger.Fatal("Error validating config:", err, lager.Data{"config": rootConfig}) } go func() { logger.Info(fmt.Sprintf("Starting profiling server on port %d", rootConfig.ProfilerPort)) err := http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", rootConfig.ProfilerPort), nil) if err != nil { logger.Error("profiler failed with error", err) } }() if _, err := os.Stat(rootConfig.StaticDir); os.IsNotExist(err) { logger.Fatal(fmt.Sprintf("staticDir: %s does not exist", rootConfig.StaticDir), nil) } backends := domain.NewBackends(rootConfig.Proxy.Backends, logger) arpManager := domain.NewArmManager(logger) cluster := domain.NewCluster( backends, rootConfig.Proxy.HealthcheckTimeout(), logger, arpManager, ) handler := api.NewHandler(backends, logger, rootConfig.API, rootConfig.StaticDir) members := grouper.Members{ { Name: "proxy", Runner: proxy.NewRunner(cluster, rootConfig.Proxy.Port, logger), }, { Name: "api", Runner: api.NewRunner(rootConfig.API.Port, handler, logger), }, } if rootConfig.HealthPort != rootConfig.API.Port { members = append(members, grouper.Member{ Name: "health", Runner: health.NewRunner(rootConfig.HealthPort, logger), }) } group := grouper.NewDynamic(os.Kill, len(members), len(members)) process := ifrit.Invoke(group) inserter := group.Client().Inserter() for _, member := range members { inserter <- member } group.Client().Close() err = waitUntilReady(process, logger) if err != nil { logger.Fatal("Error starting switchboard", err, lager.Data{"proxyConfig": rootConfig.Proxy}) } logger.Info("Proxy started", lager.Data{"proxyConfig": rootConfig.Proxy}) err = ioutil.WriteFile(rootConfig.PidFile, []byte(strconv.Itoa(os.Getpid())), 0644) if err == nil { logger.Info(fmt.Sprintf("Wrote pidFile to %s", rootConfig.PidFile)) } else { logger.Fatal("Cannot write pid to file", err, lager.Data{"pidFile": rootConfig.PidFile}) } err = <-process.Wait() if err != nil { logger.Fatal("Switchboard exited unexpectedly", err, lager.Data{"proxyConfig": rootConfig.Proxy}) } }