增加 指令支持

This commit is contained in:
dengsgo 2020-01-02 16:38:26 +08:00
parent 9defc968ba
commit 4e0b9f54f6
5 changed files with 82 additions and 7 deletions

View File

@ -20,6 +20,9 @@ const (
PreError = "ERROR:" PreError = "ERROR:"
PreWarn = "Warn:" PreWarn = "Warn:"
InstExecWhenStart = "exec-when-start"
InstShouldFinish = "should-finish"
) )
var ( var (
@ -69,11 +72,15 @@ func parseConfig() {
cfg.Monitor.IncludeDirsMap = map[string]bool{} cfg.Monitor.IncludeDirsMap = map[string]bool{}
cfg.Monitor.ExceptDirsMap = map[string]bool{} cfg.Monitor.ExceptDirsMap = map[string]bool{}
cfg.Monitor.IncludeDirsRec = map[string]bool{} cfg.Monitor.IncludeDirsRec = map[string]bool{}
cfg.Command.InstructionMap = map[string]bool{}
// convert to map // convert to map
for _, v := range cfg.Monitor.Types { for _, v := range cfg.Monitor.Types {
cfg.Monitor.TypesMap[v] = true cfg.Monitor.TypesMap[v] = true
} }
log.Println(cfg) for _, v := range cfg.Command.Instruction {
cfg.Command.InstructionMap[v] = true
}
log.Printf("%+v", cfg)
} }
func eventDispatcher(event fsnotify.Event) { func eventDispatcher(event fsnotify.Event) {
@ -249,6 +256,9 @@ func parseArgs() {
done := make(chan bool) done := make(chan bool)
initWatcher() initWatcher()
defer watcher.Close() defer watcher.Close()
if keyInInstruction(InstExecWhenStart) {
taskMan.run(new(changedFile))
}
<-done <-done
return return
case len(os.Args) > 1: case len(os.Args) > 1:

View File

@ -18,8 +18,12 @@ type FileGirl struct {
IncludeDirsRec map[string]bool `yaml:"-"` IncludeDirsRec map[string]bool `yaml:"-"`
} }
Command struct { Command struct {
Instruction []string `yaml:"instruction"`
Exec []string `yaml:"exec"` Exec []string `yaml:"exec"`
DelayMillSecond int `yaml:"delayMillSecond"` DelayMillSecond int `yaml:"delayMillSecond"`
// convert to
InstructionMap map[string]bool `yaml:"-"`
} }
Notifier struct { Notifier struct {
CallUrl string `yaml:"callUrl"` CallUrl string `yaml:"callUrl"`

14
raw.go
View File

@ -48,6 +48,20 @@ monitor:
# 命令 # 命令
command: command:
# 特殊指令 //TODO next release support
# 可以通过特殊的指令来控制 command 的行为指令可以有多个
# exec-when-start fileboy启动就绪后自动执行一次 'exec' 定义的命令
# should-finish 触发执行 'exec' (C)如果上一次的命令(L)未退出还在执行会等待 L 退出直到有明确 exit code 才会开始执行本次命令
# 在等待 L 退出时又有新事件触发了命令执行(N) C 执行取消只会保留最后一次的 N 执行
# ignore-stdout 执行 'exec' 产生的 stdout 会被丢弃
# ignore-warn fileboy 自身的 warn 信息会被丢弃
# ignore-info fileboy 自身的 info 信息会被丢弃
# ignore-exec-error 执行 'exec' 出错仍继续执行下面的命令而不退出
# limit-memory-256M 限制内存占用超过 256M 'exec' 会被强制停止格式 limit-memory-xxM
instruction:
#- should-finish
#- exec-when-start
# 监听的文件有更改会执行的命令 # 监听的文件有更改会执行的命令
# 可以有多条命令会依次执行 # 可以有多条命令会依次执行
# 如有多条命令每条命令都会等待上一条命令执行完毕后才会执行 # 如有多条命令每条命令都会等待上一条命令执行完毕后才会执行

View File

@ -15,13 +15,35 @@ type TaskMan struct {
notifier *NetNotifier notifier *NetNotifier
putLock sync.Mutex putLock sync.Mutex
runLock sync.Mutex runLock sync.Mutex
waitChan chan bool
waitQueue []*changedFile
} }
func newTaskMan(delay int, callUrl string) *TaskMan { func newTaskMan(delay int, callUrl string) *TaskMan {
return &TaskMan{ t := &TaskMan{
delay: delay, delay: delay,
notifier: newNetNotifier(callUrl), notifier: newNetNotifier(callUrl),
waitChan: make(chan bool, 1),
waitQueue: []*changedFile{},
} }
if keyInInstruction(InstShouldFinish) {
go func() {
for {
<-t.waitChan
if len(t.waitQueue) > 0 {
cf := t.waitQueue[len(t.waitQueue)-1]
if len(t.waitQueue) > 1 {
log.Println("Number of redundant tasks dropped:", len(t.waitQueue)-1)
}
t.waitQueue = []*changedFile{}
go t.preRun(cf)
}
}
}()
}
return t
} }
func (t *TaskMan) Put(cf *changedFile) { func (t *TaskMan) Put(cf *changedFile) {
@ -37,14 +59,24 @@ func (t *TaskMan) Put(cf *changedFile) {
if t.lastTaskId > cf.Changed { if t.lastTaskId > cf.Changed {
return return
} }
t.preRun(cf) if keyInInstruction(InstShouldFinish) {
t.waitQueue = append(t.waitQueue, cf)
if t.cmd == nil {
t.waitChan <- true
return
}
log.Println("Waitting for the last task to finish")
log.Println("Number of waiting tasks:", len(t.waitQueue))
} else {
t.preRun(cf)
}
}() }()
} }
func (t *TaskMan) preRun(cf *changedFile) { func (t *TaskMan) preRun(cf *changedFile) {
if t.cmd != nil && t.cmd.Process != nil { if t.cmd != nil && t.cmd.Process != nil {
log.Println("stop old process ")
if err := t.cmd.Process.Kill(); err != nil { if err := t.cmd.Process.Kill(); err != nil {
log.Println("stop old process ")
log.Println(PreWarn, "stopped err, reason:", err) log.Println(PreWarn, "stopped err, reason:", err)
} }
} }
@ -52,6 +84,13 @@ func (t *TaskMan) preRun(cf *changedFile) {
go t.notifier.Put(cf) go t.notifier.Put(cf)
} }
func (t *TaskMan) waitFinish() {
log.Println("prostate", t.cmd.Process.Pid)
if t.cmd.ProcessState != nil && !t.cmd.ProcessState.Exited() {
}
}
func (t *TaskMan) run(cf *changedFile) { func (t *TaskMan) run(cf *changedFile) {
t.runLock.Lock() t.runLock.Lock()
defer t.runLock.Unlock() defer t.runLock.Unlock()
@ -83,6 +122,9 @@ func (t *TaskMan) run(cf *changedFile) {
} }
} }
} }
if keyInInstruction(InstShouldFinish) {
t.cmd = nil
t.waitChan <- true
}
log.Println("EXEC end") log.Println("EXEC end")
} }

View File

@ -13,6 +13,11 @@ func keyInMonitorTypesMap(k string, cfg *FileGirl) bool {
return ok return ok
} }
func keyInInstruction(k string) bool {
_, ok := cfg.Command.InstructionMap[k]
return ok
}
func cmdParse2Array(s string, cf *changedFile) []string { func cmdParse2Array(s string, cf *changedFile) []string {
a := strings.Split(s, " ") a := strings.Split(s, " ")
r := make([]string, 0) r := make([]string, 0)