I try to add the necessary code to execute my app like a daemon. I used the next project:
I rewrote the sample go code that it's done: 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
}
I have added a function Writer()
that read a file, keep the text like a string and create a new file with this string.
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
}
I don't handle so good the channels in golang and I don't know why the infinite loop for in Worker()
function is executed only once...
Can you help me please?
The problem is in the Worker
function, when you try to check if you have any data in the done
channel. The receive
call will block until there is a value to be read, so that call will block until you send a signal to the process.
The second value returned from the receive operator, ok
, does not indicate whether a value was succesfully read or not. It just indicates if the channel was closed when trying to receive a value (if so the zero value
is returned, see the specification).
To check if there is a value in the channel you need to use a select
statement, like this:
select {
case v, ok <- stop:
// We could read a value from the channel
default:
// No value could be read, but we didn't block
}
So your Worker
function should look something like:
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()
}
}
Note that I have moved the Sleep
from the Writer
function to the Worker
, otherwise you would end up with thousands of concurrent Writer
go-routines...