package main import ( "context" "deploy/pkg/config" "deploy/pkg/logger" "deploy/pkg/server" "deploy/pkg/tools" "flag" "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/sirupsen/logrus" "gopkg.in/fsnotify.v1" ) var cfgPath string = "./config.yml" func main() { flag.StringVar(&cfgPath, "c", "./config.yml", "config yaml path") flag.Parse() if !tools.CheckExists(cfgPath, false) { log.Fatal(fmt.Errorf("config file not exists")) } // lock for service running // buffer count 5 reloadChan := make(chan struct{}, 5) // lock for main lock lock := make(chan os.Signal, 1) signal.Notify(lock, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL) watcher, err := fsnotify.NewWatcher() if err != nil { log.Fatal(err) } defer watcher.Close() go func() { for { select { case event, ok := <-watcher.Events: if !ok { // channel closed return } if event.Op&fsnotify.Write == fsnotify.Write { // send reload channel reloadChan <- struct{}{} } case err, ok := <-watcher.Errors: if !ok { // channel closed return } log.Fatal(err) } } }() if err := watcher.Add(cfgPath); err != nil { log.Fatal(err) } go runService(reloadChan) <-lock close(reloadChan) } func runService(reload <-chan struct{}) { lastReload := time.Now() log := logger.NewLogger(nil) var svc *http.Server // infinity loop for { if svc == nil { svc = startServer(log) } select { case _, ok := <-reload: if !ok { // channel closed exit program if err := stopServer(svc); err != nil { log.Fatal(err) return } } if time.Since(lastReload).Seconds() < float64(2*time.Second) { break } lastReload = time.Now() if err := stopServer(svc); err != nil { log.Fatal(err) } svc = nil } } } func startServer(log *logrus.Logger) *http.Server { cfg, err := config.Load(cfgPath) if err != nil { log.Fatal(err) } engine := server.NewServer(log) // set routes if err := engine.SetRoutes(cfg.Listens); err != nil { log.Fatal(err) } svc := &http.Server{ Addr: fmt.Sprintf(":%d", cfg.Server.Port), Handler: engine.Engine, } go func() { if err := svc.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatal(err) } }() return svc } func stopServer(svc *http.Server) error { ctx, cancel := context.WithTimeout(context.Background(), time.Second*1) defer cancel() if err := svc.Shutdown(ctx); err != nil { return err } return nil }