summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2020-02-20 14:14:11 +0300
committerValery Piashchynski <[email protected]>2020-02-20 14:14:11 +0300
commit2efcfeb89861ba981f980bb4503c31ca6c7a92e0 (patch)
tree22269a5cecc888cd26d6b1bd8477f30ea604ba21
parentec7975355a8acea632e5c9b7e912b3e9ad6907ca (diff)
Declare general interfaces, Controllable and Attacher instead of private
First dirty working example of reload
-rw-r--r--controller.go6
-rw-r--r--server.go6
-rw-r--r--service/limit/service.go8
-rw-r--r--service/reload/config.go12
-rw-r--r--service/reload/service.go122
-rw-r--r--service/reload/watcher.go116
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
diff --git a/server.go b/server.go
index 8f8e9382..406bc0a0 100644
--- a/server.go
+++ b/server.go
@@ -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}:
+ // }
+ //}
}