diff options
author | Valery Piashchynski <[email protected]> | 2020-02-20 14:14:11 +0300 |
---|---|---|
committer | Valery Piashchynski <[email protected]> | 2020-02-20 14:14:11 +0300 |
commit | 2efcfeb89861ba981f980bb4503c31ca6c7a92e0 (patch) | |
tree | 22269a5cecc888cd26d6b1bd8477f30ea604ba21 | |
parent | ec7975355a8acea632e5c9b7e912b3e9ad6907ca (diff) |
Declare general interfaces, Controllable and Attacher instead of private
First dirty working example of reload
-rw-r--r-- | controller.go | 6 | ||||
-rw-r--r-- | server.go | 6 | ||||
-rw-r--r-- | service/limit/service.go | 8 | ||||
-rw-r--r-- | service/reload/config.go | 12 | ||||
-rw-r--r-- | service/reload/service.go | 122 | ||||
-rw-r--r-- | service/reload/watcher.go | 116 |
6 files changed, 165 insertions, 105 deletions
diff --git a/controller.go b/controller.go index bda7ad6b..020ea4dd 100644 --- a/controller.go +++ b/controller.go @@ -8,3 +8,9 @@ type Controller interface { // Detach pool watching. Detach() } + +// Attacher defines the ability to attach rr controller. +type Attacher interface { + // Attach attaches controller to the service. + Attach(c Controller) +}
\ No newline at end of file @@ -23,6 +23,12 @@ const ( EventPoolDestruct ) +// Controllable defines the ability to attach rr controller. +type Controllable interface { + // Server represents RR server + Server() *Server +} + // Server manages pool creation and swapping. type Server struct { // configures server, pool, cmd creation and factory. diff --git a/service/limit/service.go b/service/limit/service.go index 6af571e2..c0b4139c 100644 --- a/service/limit/service.go +++ b/service/limit/service.go @@ -8,12 +8,6 @@ import ( // ID defines controller service name. const ID = "limit" -// controllable defines the ability to attach rr controller. -type controllable interface { - // Attach attaches controller to the service. - Attach(c roadrunner.Controller) -} - // Service to control the state of rr service inside other services. type Service struct { lsns []func(event int, ctx interface{}) @@ -24,7 +18,7 @@ func (s *Service) Init(cfg *Config, c service.Container) (bool, error) { // mount Services to designated services for id, watcher := range cfg.Controllers(s.throw) { svc, _ := c.Get(id) - if ctrl, ok := svc.(controllable); ok { + if ctrl, ok := svc.(roadrunner.Attacher); ok { ctrl.Attach(watcher) } } diff --git a/service/reload/config.go b/service/reload/config.go index fb704015..f684a227 100644 --- a/service/reload/config.go +++ b/service/reload/config.go @@ -1,6 +1,9 @@ package reload -import "github.com/spiral/roadrunner/service" +import ( + "github.com/spiral/roadrunner" + "github.com/spiral/roadrunner/service" +) // Config is a Reload configuration point. type Config struct { @@ -20,11 +23,13 @@ type ServiceConfig struct { // Patterns is per-service specific files to watch Patterns []string // Dirs is per-service specific dirs which will be combined with Patterns - Dirs []string + Dirs []string // Ignore is set of files which would not be watched Ignore []string -} + // service is a link to service to restart + service *roadrunner.Controllable +} // Hydrate must populate Config values using given Config source. Must return error if Config is not valid. func (c *Config) Hydrate(cfg service.Config) error { @@ -40,4 +45,3 @@ func (c *Config) InitDefaults() error { return nil } - diff --git a/service/reload/service.go b/service/reload/service.go index 5a400159..9b3ac2f0 100644 --- a/service/reload/service.go +++ b/service/reload/service.go @@ -1,6 +1,8 @@ package reload import ( + "fmt" + "github.com/spiral/roadrunner" "github.com/spiral/roadrunner/service" "os" "strings" @@ -12,79 +14,111 @@ const ID = "reload" type Service struct { reloadConfig *Config - container service.Container watcher *Watcher + } // Init controller service func (s *Service) Init(cfg *Config, c service.Container) (bool, error) { - s.container = c s.reloadConfig = cfg - return true, nil -} + var err error + var configs []WatcherConfig + + // mount Services to designated services + for serviceName, _ := range cfg.Services { + svc, _ := c.Get(serviceName) + if ctrl, ok := svc.(roadrunner.Controllable); ok { + tmp := cfg.Services[serviceName] + tmp.service = &ctrl + cfg.Services[serviceName] = tmp + } + } -func (s *Service) Serve() error { - if !s.reloadConfig.Enabled { - return nil + + + for serviceName, config := range s.reloadConfig.Services { + if cfg.Services[serviceName].service == nil { + continue + } + configs = append(configs, WatcherConfig{ + serviceName: serviceName, + recursive: config.Recursive, + directories: config.Dirs, + filterHooks: func(filename, pattern string) error { + if strings.Contains(filename, pattern) { + return ErrorSkip + } + return nil + }, + files: make(map[string]os.FileInfo), + //ignored: + }) } - var err error - s.watcher, err = NewWatcher([]WatcherConfig{WatcherConfig{ - serviceName: "test_service_name", - recursive: false, - directories: []string{"/service"}, - filterHooks: func(filename, pattern string) error { - if strings.Contains(filename, pattern) { - return ErrorSkip - } - return nil - }, - files: make(map[string]os.FileInfo), - //ignored: []string{".php"}, - }}) + s.watcher, err = NewWatcher(configs) if err != nil { - return err + return false, err } + for serviceName, config := range s.reloadConfig.Services { + svc, _ := c.Get(serviceName) + if ctrl, ok := svc.(*roadrunner.Controllable); ok { + (*ctrl).Server().Reset() + } + configs = append(configs, WatcherConfig{ + serviceName: serviceName, + recursive: config.Recursive, + directories: config.Dirs, + filterHooks: func(filename, pattern string) error { + if strings.Contains(filename, pattern) { + return ErrorSkip + } + return nil + }, + files: make(map[string]os.FileInfo), + //ignored: + + }) + } - s.watcher.AddSingle("test_service_name", "/service") + return true, nil +} +func (s *Service) Serve() error { + if !s.reloadConfig.Enabled { + return nil + } go func() { for { select { case e := <-s.watcher.Event: - println(e.Type) + println(fmt.Sprintf("type is:%s, oldPath:%s, path:%s, name:%s", e.Type, e.OldPath, e.Path, e.FileInfo.Name())) + + srv := s.reloadConfig.Services[e.Type] + + if srv.service != nil { + s := *srv.service + err := s.Server().Reset() + if err != nil { + fmt.Println(err) + } + } else { + s.watcher.mu.Lock() + delete(s.watcher.watcherConfigs, e.Type) + s.watcher.mu.Unlock() + } } } - //for e = range w.Event { - // - // println("event") - // // todo use status - // //svc, _ := s.container.Get("http") - // //if svc != nil { - // // if srv, ok := svc.(service.Service); ok { - // // srv.Stop() - // // err = srv.Serve() - // // if err != nil { - // // return err - // // } - // // } - // //} - // - // //println("event skipped due to service is nil") - //} }() - err = s.watcher.StartPolling(time.Second) + err := s.watcher.StartPolling(time.Second * 2) if err != nil { return err } - // read events and restart corresponding services - return nil } diff --git a/service/reload/watcher.go b/service/reload/watcher.go index 7b224319..8b1ee7b2 100644 --- a/service/reload/watcher.go +++ b/service/reload/watcher.go @@ -87,6 +87,7 @@ type Watcher struct { operations map[Op]struct{} // Op filtering. // config for each service + // need pointer here to assign files watcherConfigs map[string]WatcherConfig } @@ -125,9 +126,27 @@ func NewWatcher(configs []WatcherConfig, options ...Options) (*Watcher, error) { return nil, NoWalkerConfig } + err = w.initFs() + if err != nil { + return nil, err + } + return w, nil } +func (w *Watcher) initFs() error { + for srvName, config := range w.watcherConfigs { + fileList, err := w.retrieveFileList(srvName, config) + if err != nil { + return err + } + tmp := w.watcherConfigs[srvName] + tmp.files = fileList + w.watcherConfigs[srvName] = tmp + } + return nil +} + func (w *Watcher) AddWatcherConfig(config WatcherConfig) { w.watcherConfigs[config.serviceName] = config } @@ -310,7 +329,6 @@ func (w *Watcher) StartPolling(duration time.Duration) error { func (w *Watcher) waitEvent(d time.Duration) error { for { cancel := make(chan struct{}) - ticker := time.NewTicker(d) for { select { @@ -324,16 +342,10 @@ func (w *Watcher) waitEvent(d time.Duration) error { for serviceName, config := range w.watcherConfigs { go func(sn string, c WatcherConfig) { - w.wg.Add(1) fileList, _ := w.retrieveFileList(sn, c) w.pollEvents(c.serviceName, fileList, cancel) - w.wg.Done() }(serviceName, config) } - - w.wg.Wait() - - //w.mu.Unlock() default: } @@ -342,6 +354,8 @@ func (w *Watcher) waitEvent(d time.Duration) error { } func (w *Watcher) retrieveFileList(serviceName string, config WatcherConfig) (map[string]os.FileInfo, error) { + w.mu.Lock() + defer w.mu.Unlock() fileList := make(map[string]os.FileInfo) if config.recursive { // walk through directories recursively @@ -360,7 +374,6 @@ func (w *Watcher) retrieveFileList(serviceName string, config WatcherConfig) (ma } } - for _, dir := range config.directories { absPath, err := filepath.Abs(w.workingDir) if err != nil { @@ -466,6 +479,9 @@ func (w *Watcher) pollEvents(serviceName string, files map[string]os.FileInfo, c // Check for created files, writes and chmods. for pth, info := range files { + if info.IsDir() { + continue + } oldInfo, found := w.watcherConfigs[serviceName].files[pth] if !found { // A file was created. @@ -491,46 +507,46 @@ func (w *Watcher) pollEvents(serviceName string, files map[string]os.FileInfo, c } // Check for renames and moves. - for path1, info1 := range removes { - for path2, info2 := range creates { - if sameFile(info1, info2) { - e := Event{ - Op: Move, - Path: path2, - OldPath: path1, - FileInfo: info1, - } - // If they are from the same directory, it's a rename - // instead of a move event. - if filepath.Dir(path1) == filepath.Dir(path2) { - e.Op = Rename - } - - delete(removes, path1) - delete(creates, path2) - - select { - case <-cancel: - return - case w.Event <- e: - } - } - } - } - - // Send all the remaining create and remove events. - for path, info := range creates { - select { - case <-cancel: - return - case w.Event <- Event{Create, path, "", info, "http"}: - } - } - for path, info := range removes { - select { - case <-cancel: - return - case w.Event <- Event{Remove, path, path, info, "http"}: - } - } + //for path1, info1 := range removes { + // for path2, info2 := range creates { + // if sameFile(info1, info2) { + // e := Event{ + // Op: Move, + // Path: path2, + // OldPath: path1, + // FileInfo: info1, + // } + // // If they are from the same directory, it's a rename + // // instead of a move event. + // if filepath.Dir(path1) == filepath.Dir(path2) { + // e.Op = Rename + // } + // + // delete(removes, path1) + // delete(creates, path2) + // + // select { + // case <-cancel: + // return + // case w.Event <- e: + // } + // } + // } + //} + // + ////Send all the remaining create and remove events. + //for pth, info := range creates { + // select { + // case <-cancel: + // return + // case w.Event <- Event{Create, pth, pth, info, serviceName}: + // } + //} + //for pth, info := range removes { + // select { + // case <-cancel: + // return + // case w.Event <- Event{Remove, pth, pth, info, serviceName}: + // } + //} } |