2017-05-29 97 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