Daemon executes only one time a goroutine

Hello all,

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?

Thank you!

The for loop waits for the stop channel to emit a struct{}. The stop channel is unbuffered, so <-stop waits until someone writes into stop. This blocks the for loop after the first call to go Writer().

Use select instead of if to read from stop:

for {
    Loop:
    go Writer()
    select {
        case <-stop:
            break Loop
        default:
    }
}

Be aware, however, that the infinite for loop produces Writer goroutines nonstop. At least on a single-core CPU, neither the Writers nor the main routine would not have a chance to run at all.

Here is a stripped-down and modified version of your code. It adds Sleep() to Worker() and replaces the if by a select:

package main

import (
        "fmt"
        "time"
)

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

func main() {
        go Worker()

        time.Sleep(20 * time.Second)
        fmt.Println("Stop")
        stop <- struct{}{}
        <-done
}

func Worker() {
        Loop:
        for {
                go Writer()
                time.Sleep(time.Second)
                select {
                case <-stop:
                        fmt.Println("Stop received")
                        break Loop
                default:
                }
        }
        done <- struct{}{}
}

func Writer() {
        time.Sleep(10 * time.Second)

        fmt.Println("Writer")
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.