golang webapp init.d 脚本挂起

标签 go upstart init.d

我有一个编译为单个二进制文件的 go web 应用程序,我试图通过 init.d 进行管理。这是我的 init.d 脚本:

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/my-go-app
DAEMON_ARGS="--logFile /var/log/my-go-app/my-go-app.log"
NAME=my-go-app
DESC=my-go-app

RUNDIR=/var/run/my-go-app
PIDFILE=$RUNDIR/my-go-app.pid

test -x $DAEMON || exit 0

if [ -r /etc/default/$NAME ]
then
        . /etc/default/$NAME
fi

. /lib/lsb/init-functions

set -e

case "$1" in
  start)
        echo -n "Starting $DESC: "
        mkdir -p $RUNDIR
        touch $PIDFILE
        chown ubuntu:ubuntu $RUNDIR $PIDFILE
        chmod 755 $RUNDIR

        if [ -n "$ULIMIT" ]
        then
                ulimit -n $ULIMIT
        fi

        if start-stop-daemon --start --quiet --umask 007 --pidfile $PIDFILE --chuid ubuntu:ubuntu --exec $DAEMON -- $DAEMON_ARGS
        then
                echo "$NAME."
        else
                echo "failed"
        fi
                ;;
  stop)
        echo -n "Stopping $DESC: "
        if start-stop-daemon --stop --retry forever/TERM/1 --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON
        then
                echo "$NAME."
        else
                echo "failed"
        fi
        rm -f $PIDFILE
        sleep 1
        ;;

  restart|force-reload)
        ${0} stop
        ${0} start
        ;;

  status)
        echo -n "$DESC is "
        if start-stop-daemon --stop --quiet --signal 0 --name ${NAME} --pidfile ${PIDFILE}
        then
                echo "running"
        else
                echo "not running"
                exit 1
        fi
        ;;

  *)
        echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|status}" >&2
        exit 1
        ;;
esac

exit 0

问题是,当我运行 service my-go-app start 时,它只是挂起,如下所示:

ubuntu@ip-10-0-0-40:~$ service my-go-app start
Starting my-go-app:

永远不会回来。在这种状态下,如果我打开一个单独的终端,我可以通过检查日志文件看到应用程序正在运行,但是/var/run/my-go-app/my-go-app.pid 中没有任何内容(尽管pid 文件确实被创建了)。

有没有人遇到过(并希望解决过)这个问题?如何将我的 go 应用作为 init.d 守护进程运行?

编辑: 我能够通过在启动服务时将“-b -m”命令行标志添加到 start-stop-daemon 来让它工作。该行现在看起来像这样:

start-stop-daemon -b -m --start --quiet --umask 007 --pidfile $PIDFILE --chuid ubuntu:ubuntu --exec $DAEMON -- $DAEMON_ARGS

我对这种方法的担忧是 start-stop-daemon 联机帮助页中的警告:

-b, --background
              Typically used with programs that don't detach on their own. This option will force start-stop-daemon to fork before starting the process,  and
              force  it into the background.  WARNING: start-stop-daemon cannot check the exit status if the process fails to execute for any reason. This is
              a last resort, and is only meant for programs that either make no sense forking on their own, or where it's not feasible to add  the  code  for
              them to do this themselves.

这对我来说似乎是个坏主意,因为听起来 SysV 不知道进程是否终止。我理解正确吗?有没有其他人尝试过这种方法?

最佳答案

如果您正在运行带有 Upstart 的系统,您可以使用此脚本:

start on runlevel [2345]
stop on runlevel [016] or unmounting-filesystem

# Replace {soft} and {hard} with the soft and hard resource limits you desire
#limit nofile {soft} {hard}

umask 007

setuid ubuntu
setgid ubuntu

exec /usr/bin/my-go-app --logFile /var/log/my-go-app/my-go-app.log

您还可以在您的应用程序已启动并正确初始化的位置将以下代码添加到您的守护程序中:

if ("yes" == os.Getenv("MYAPP_RAISESTOP")) {
    p, err := os.FindProcess(os.Getpid())
    p.Signal(syscall.SIGSTOP)
}

以及上述 upstart 工作的以下行:

env MYAPP_RAISESTOP="yes"
expect stop

如果 if () { } 不是真正的 Go 语法,我很抱歉;我是一个 C 程序员哈哈(虽然 () 和 {} 里面的东西是真实的,我做了一点研究:)。

最后一点确保 Upstart 会等到您的应用程序正确设置后才会触发 started 事件。如果没有其他工作在等待您的应用程序,那么您真的不需要它。

关于golang webapp init.d 脚本挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25494400/

相关文章:

http - 返回错误之前如何收集尽可能多的信息

node.js - 如何自动重启 Node 服务器?

linux -/etc/init.d/functions 中的声明在 EL 5 上的含义

Bash 脚本 - 编写 init.d 脚本

raspberry-pi - Raspberry Pi 脚本启动顺序

go - 如何获取本地时区的全名?

go - 如何在golang中解析https原始字节

go - MQTT现有客户端

php - 如何守护一个 php 脚本以与 upstart 一起运行

ubuntu - 使用 upstart 在 ubuntu 上运行 Python 服务