英文:
Receive from non-chan type *bool
问题
我想将myapp变成守护进程,但是我遇到了一个大问题。我正在使用的通道的类型是chan struct{}。然而,使用getopt(flag包)时,我的标志的类型是*bool,所以我不知道如何修改myapp。
仅仅使用bool类型的通道是不够的。我确定有一个概念我不理解。我附上了代码:
package main
import (
	"os"
	"syscall"
	"time"
	
	"github.com/pborman/getopt/v2"
	"github.com/sevlyar/go-daemon"
)
var (
	done   = make(chan struct{})
	optQuit = make(chan struct{})
	optRun  = make(chan struct{})
)
func TermHandler(sig os.Signal) error {
	optQuit <- struct{}{}
	if sig == syscall.SIGQUIT {
		<-done
	}
	return nil
}
func main() {
	optHelp := getopt.BoolLong("help", 'h', "Help")
	optQuit := getopt.BoolLong("quit", 0, "Help")
	optRun  := getopt.BoolLong("run", 'r', "Help")
	
	if *optHelp {
		getopt.Usage()
		os.Exit(0)
	}
	// 创建pid文件
	cntxt := &daemon.Context{
		PidFileName: "/var/run/myapp.pid",
		PidFilePerm: 0644,
		WorkDir:     "./",
		Umask:       027,
		Args:        []string{"[Z]"},
	}
	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()
	// 定义ticker
	ticker := time.NewTicker(time.Second)
	myapp := true
	
	// 循环
	for myapp {
		select {
		// Case sleep
		case <-ticker.C:
			time.Sleep(time.Second)
		// Case QUIT
		case <-optQuit:
			done <- struct{}{}
			myapp = false
			ticker.Stop()
			os.Exit(0)
		// Case RUN
		case <-optRun:
			// 执行一个goroutine...
		}
	}
}
使用go install命令,我看到了以下错误:
./main.go:72: invalid operation: <-optQuit (receive from non-chan type *bool)
./main.go:79: invalid operation: <-optRun (receive from non-chan type *bool)
我不知道我应该如何修改通道(done、optQuit的类型为struct{}),以解决这个问题...
附注:我向你展示了一个我做的示例。它作为守护进程运行,并且每分钟执行一次Writer()函数。然后,如果你输入zdaemon -z quit,应用程序会进行优雅关闭。你可以在你的机器上运行它:
https://play.golang.org/p/RVq7M7usEj
英文:
I want to daemonize myapp but I have one big problem. The channels I'm using are of type chan struct{}.
However, with the package getopt (flag package), my flags are of type *bool, so I don't know how can I modify myapp.
It's not enough with channels type bool. I'm sure there are a concept that I don't understand. I attach you the code:
package main
import (
"os"
"syscall"
"time"
"github.com/pborman/getopt/v2"
"github.com/sevlyar/go-daemon"
)
var (
done	= make(chan struct{})
optQuit = make(chan struct{})
optRun  = make(chan struct{})
)
func TermHandler(sig os.Signal) error {
optQuit <- struct{}{}
if sig == syscall.SIGQUIT {
<-done
}
return nil
}
func main() {
optHelp := getopt.BoolLong("help", 'h', "Help")
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun  := getopt.BoolLong("run", 'r', "Help")
if *optHelp {
getopt.Usage()
os.Exit(0)
}
// Create pid file
cntxt := &daemon.Context{
PidFileName: "/var/run/myapp.pid",
PidFilePerm: 0644,
WorkDir:     "./",
Umask:       027,
Args:        []string{"[Z]"},
}
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()
// Define ticker
ticker := time.NewTicker(time.Second)
myapp := true
// Loop
for myapp {
select {
// Case sleep
case <- ticker.C:
time.Sleep(time.Second)
// Case QUIT
case <- optQuit:
done <- struct{}{}
myapp = false
ticker.Stop()
os.Exit(0)
// Case RUN
case <- optRun:
// Executes a goroutine...
}
}
}
With go install, I can see this errors:
./main.go:72: invalid operation: <-optQuit (receive from non-chan type *bool)
./main.go:79: invalid operation: <-optRun (receive from non-chan type *bool)
I don't know how I should modify the channels (done, optQuit of type struct{}), to resolve this...
P.S.: I show you an example that I did. It runs as daemon and each minute, it executes the function Writer().
After, if you type zdaemon -z quit, the app does a graceful shutdown. You can run it in your machines:
答案1
得分: 0
你的主函数中的这两行代码遮盖了全局变量的声明:
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun  := getopt.BoolLong("run", 'r', "Help")
如果你只是用它们来获得一个漂亮的用法,为什么不自己创建一个用法函数呢?
如果你坚持使用 getopt 来创建用法,可以这样做:
_ = getopt.BoolLong("quit", 0, "Help")
_ = getopt.BoolLong("run", 'r', "Help")
而不是赋值给变量。
在使用 *optHelp 之前,你还需要调用 getopt.Parse()。
生成的消息
Usage: test [-hr] [--quit] [parameters ...]
-h, --help  Help
--quit  Help
-r, --run   Help
似乎不太有帮助。为什么不直接这样做:
fmt.Printf(`
Usage: test
This program will start a daemon service, which you can use like this ...
`)
英文:
Those two lines in your main function shadow your global variable declaration:
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun  := getopt.BoolLong("run", 'r', "Help")
If you only use them, to get a nice usage, why not create a usage function
yourself?
If you insist on using getopt just to create a usage, do
_ = getopt.BoolLong("quit", 0, "Help")
_ = getopt.BoolLong("run", 'r', "Help")
instead.
You also need to call getopt.Parse() before using *optHelp.
The resulting message
Usage: test [-hr] [--quit] [parameters ...]
-h, --help  Help
--quit  Help
-r, --run   Help
seems to be less than helpful. Why not just do
fmt.Printf(`
Usage: test
This program will start a daemon service, which you can use like this ...
`)
答案2
得分: 0
你在全局定义了optQuit = make(chan struct{}),然后在main函数中将其遮蔽了:optQuit := getopt.BoolLong("quit", 0, "Help")。
所以在main函数中,optQuit是一个bool类型,而不是一个chan类型。
请在main函数中删除这两行代码:
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun  := getopt.BoolLong("run", 'r', "Help")
英文:
You define optQuit = make(chan struct{}) globally and then shadow it in main: optQuit := getopt.BoolLong("quit", 0, "Help").
So in main optQuit is a bool, not a chan
Remove those two lines in main:
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun  := getopt.BoolLong("run", 'r', "Help")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论