因此我编写了一个 golang 应用程序,我希望systemd
每次服务器重启时都初始化它。
这是服务文件:-
[Unit]
Description=golang wiki initialization
[Service]
Type=forking
PIDFile=/tmp/gowiki.pid-3030
User=root
Group=root
WorkingDirectory=/var/www
ExecStart=/bin/bash -c 'daemonize -o stdout.log -e stderr.log /var/www/wiki'
[Install]
WantedBy=multi-user.target
每当我重新启动服务器时,它似乎都能正常工作,但是当我gowiki
在终端中手动启动或重新启动时,仍然会遇到稍微令人恼火的问题:-
systemctl start gowiki
或者
systemctl restart gowiki
这确实使我的 gowiki 进程运行;但是,执行命令后systemctl start gowiki
,我的终端被冻结,并且命令似乎没有退出,直到我手动强制按 Ctrl-C。
我做错了什么导致了这个问题?
答案1
这有效。
[Unit]
Description=golang wiki initialization
[Service]
PIDFile=/tmp/gowiki.pid-4040
User=root
Group=root
WorkingDirectory=/var/www
ExecStart=/bin/bash -c '/var/www/wiki'
[Install]
WantedBy=multi-user.target
因为Type=forking
服务期望父服务在实际启动之前退出。如果父服务从未退出,则 systemctl start 将不会返回提示,因为它认为它尚未完成执行。
答案2
如果您不介意针对 systemd 稍微调整一下代码,那么迄今为止我发现的最干净的解决方案是使用 SDNotify 信号。
import "github.com/coreos/go-systemd/daemon"
func main() {
// Important init stuff here
....
// Notify systemd that we're ready
sent, e := daemon.SdNotify(false, "READY=1")
if e != nil {
log.Fatal(e)
}
if !sent {
log.Printf("SystemD notify NOT sent\n")
}
// And do something blocking like listening for HTTP(s)
- 它没有 CGO-deps
- 该代码也可在非 systemd 系统上运行(在这种情况下,它会发出警告“通知未发送”)
- 如果你想要一个可以工作的例子:https://github.com/mpdroog/dnsleak
您对应的 systemd 单元文件:
[Unit]
Description=golang wiki initialization
After=network.target
Requires=network.target
[Service]
Type=notify
Restart=always
RestartSec=30
TimeoutStartSec=0
WorkingDirectory=/var/www
ExecStart=/var/www/wiki
User=www-data
Group=www-data
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target