英文:
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")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论