From 4e0b9f54f6dae8c5a74d2eb290f62b551cb381b3 Mon Sep 17 00:00:00 2001 From: dengsgo Date: Thu, 2 Jan 2020 16:38:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fileboy.go | 12 +++++++++++- filegirl.go | 4 ++++ raw.go | 14 ++++++++++++++ taskman.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++------ util.go | 5 +++++ 5 files changed, 82 insertions(+), 7 deletions(-) diff --git a/fileboy.go b/fileboy.go index be15624..9d2d01e 100644 --- a/fileboy.go +++ b/fileboy.go @@ -20,6 +20,9 @@ const ( PreError = "ERROR:" PreWarn = "Warn:" + + InstExecWhenStart = "exec-when-start" + InstShouldFinish = "should-finish" ) var ( @@ -69,11 +72,15 @@ func parseConfig() { cfg.Monitor.IncludeDirsMap = map[string]bool{} cfg.Monitor.ExceptDirsMap = map[string]bool{} cfg.Monitor.IncludeDirsRec = map[string]bool{} + cfg.Command.InstructionMap = map[string]bool{} // convert to map for _, v := range cfg.Monitor.Types { 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) { @@ -249,6 +256,9 @@ func parseArgs() { done := make(chan bool) initWatcher() defer watcher.Close() + if keyInInstruction(InstExecWhenStart) { + taskMan.run(new(changedFile)) + } <-done return case len(os.Args) > 1: diff --git a/filegirl.go b/filegirl.go index 86cfea3..86f305c 100644 --- a/filegirl.go +++ b/filegirl.go @@ -18,8 +18,12 @@ type FileGirl struct { IncludeDirsRec map[string]bool `yaml:"-"` } Command struct { + Instruction []string `yaml:"instruction"` Exec []string `yaml:"exec"` DelayMillSecond int `yaml:"delayMillSecond"` + + // convert to + InstructionMap map[string]bool `yaml:"-"` } Notifier struct { CallUrl string `yaml:"callUrl"` diff --git a/raw.go b/raw.go index fdc90f5..ff4c0c0 100644 --- a/raw.go +++ b/raw.go @@ -48,6 +48,20 @@ monitor: # 命令 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 + # 监听的文件有更改会执行的命令 # 可以有多条命令,会依次执行 # 如有多条命令,每条命令都会等待上一条命令执行完毕后才会执行 diff --git a/taskman.go b/taskman.go index 6c93c6f..06b9c84 100644 --- a/taskman.go +++ b/taskman.go @@ -15,13 +15,35 @@ type TaskMan struct { notifier *NetNotifier putLock sync.Mutex runLock sync.Mutex + + waitChan chan bool + waitQueue []*changedFile } func newTaskMan(delay int, callUrl string) *TaskMan { - return &TaskMan{ - delay: delay, - notifier: newNetNotifier(callUrl), + t := &TaskMan{ + delay: delay, + 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) { @@ -37,14 +59,24 @@ func (t *TaskMan) Put(cf *changedFile) { if t.lastTaskId > cf.Changed { 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) { if t.cmd != nil && t.cmd.Process != nil { - log.Println("stop old process ") if err := t.cmd.Process.Kill(); err != nil { + log.Println("stop old process ") log.Println(PreWarn, "stopped err, reason:", err) } } @@ -52,6 +84,13 @@ func (t *TaskMan) preRun(cf *changedFile) { 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) { t.runLock.Lock() 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") } diff --git a/util.go b/util.go index d8ba13d..1bf8e52 100644 --- a/util.go +++ b/util.go @@ -13,6 +13,11 @@ func keyInMonitorTypesMap(k string, cfg *FileGirl) bool { return ok } +func keyInInstruction(k string) bool { + _, ok := cfg.Command.InstructionMap[k] + return ok +} + func cmdParse2Array(s string, cf *changedFile) []string { a := strings.Split(s, " ") r := make([]string, 0)