2017-05-29 74 views
1

我尝试添加必要的代码来像守护进程一样执行我的应用程序。我使用的下一个项目:守护进程只执行一次goroutine

  • github.com/sevlyar/go-daemon

我重写,它的完成样品Go代码: https://github.com/sevlyar/go-daemon/blob/master/sample/sample.go

package main 

import (
    "bufio" 
    "flag" 
    "fmt" 
    "io/ioutil" 
    "os" 
    "syscall" 
    "time" 

    "github.com/sevlyar/go-daemon" 
) 

var (
    signal = flag.String("s", "", `sdaemon -s ... 
     quit -- graceful shutdown`) 
) 

var (
    stop = make(chan struct{}) 
    done = make(chan struct{}) 
) 

func main() { 
    flag.Parse() 
    daemon.AddCommand(daemon.StringFlag(signal, "quit"), syscall.SIGQUIT, TermHandler) 

    cntxt := &daemon.Context{ 
     PidFileName: "/var/run/sdaemon.pid", 
     PidFilePerm: 0644, 
     WorkDir:  "./", 
     Umask:  027, 
     Args:  []string{"[sdaemon]"}, 
    } 
    if len(daemon.ActiveFlags()) > 0 { 
     d, _ := cntxt.Search() 
     daemon.SendCommands(d) 
     return 
    } 
    d, err := cntxt.Reborn() 
    if d != nil { 
     return 
    } 
    if err != nil { 
     os.Exit(1) 
    } 
    defer cntxt.Release() 

    // Start daemon 
    go Worker() 

    err = daemon.ServeSignals() 
    if err != nil { 
     fmt.Printf("STOPPED!\n") 
     return 
    } 
} 

func Worker() { 
    for { 
     go Writer() 
     if _, ok := <-stop; ok { 
      break 
     } 
    } 
    done <- struct{}{} 
} 

func TermHandler(sig os.Signal) error { 
    stop <- struct{}{} 
    if sig == syscall.SIGQUIT { 
     <-done 
    } 
    return daemon.ErrStop 
} 

我添加了一个功能Writer()读取文件,保持文本像一个字符串,并创建一个新的文件与此字符串。

func Writer() error { 
    time.Sleep(time.Minute) 

    f, _ := ioutil.ReadFile("$HOME/test") 
    contents := string(f) 

    fileHandle, _ := os.Create("$HOME/stest") 
    writer := bufio.NewWriter(fileHandle) 
    defer fileHandle.Close() 
    fmt.Fprintln(writer, contents) 
    writer.Flush() 

    return nil 
} 

我不处理好中golang渠道,我不知道为什么只执行一次在Worker()功能的无限循环......

你能帮助我吗?

回答

1

问题出在Worker函数中,当您尝试检查您是否在done频道中有数据时。 receive调用将阻塞,直到有值被读取,以便呼叫将阻塞,直到您发送信号给进程。

接收运算符ok返回的第二个值不表示值是否成功读取。它只是表示尝试接收值时通道是否关闭(如果是这样,返回zero value,请参阅the specification)。

要检查是否有在渠道,你需要使用select语句,像这样的值:

select { 
     case v, ok <- stop: 
      // We could read a value from the channel 
     default: 
      // No value could be read, but we didn't block 
} 

所以你Worker功能应该是这个样子:

func Worker() { 
    for { 
     time.Sleep(time.Minute) 
     select { 
     case <- stop: 
      // Got a stop signal, stopping 
      done <- struct{}{} 
      return 
     default: 
      // No stop signal, continuing loop 
     } 

     go Writer() 
    } 
} 

注意我已将SleepWriter函数移至Worker,否则最终会出现数千个并行Writer例程...

+0

现在'Writer()'函数可以工作,但是当我键入'sdaemon -s quit'来执行正常关机时,在它工作之前它不起作用;你知道什么问题?非常感谢你的第一次解析@johlo – icarbajo

+0

我有答案,'sdaemon -s quit'可以工作,但我们必须等待time.Sleep()才能正常关机。我需要改变这一点。 – icarbajo

+1

@icvallejo您可能想使用“Ticker”代替睡眠,请参阅https://gobyexample.com/tickers。当SIGQUIT信号到来时,您可以停止收报机。 – johlo