golang webapp init.d脚本挂起

I have a go web app compiled to a single binary that I am trying to manage via init.d. Here is my init.d script:

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

The problem is that when I run service my-go-app start, it just hangs, like this:

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

and never returns. In this state, if I open a separate terminal, I can see that the app is running by checking the log file but there is nothing in /var/run/my-go-app/my-go-app.pid (though the pid file does get created).

Has anyone encountered (and hopefully resolved) this before? How can I run my go app as an init.d daemon?

EDIT: I was able to get this to work by adding the "-b -m" command line flags to start-stop-daemonwhen starting the service. That line now looks like this:

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

My concern with this approach is the warning in the start-stop-daemon manpage:

-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.

This seems like a bad idea to me, because it sounds like SysV won't know if the process dies. Am I understanding this correctly? Has anyone else tried this approach?

If you are running a system with Upstart you can use this script:

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

You can also add the following code to your daemon at a point where your application has been started and initialized correctly:

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

and the following to lines to the above upstart job:

env MYAPP_RAISESTOP="yes"
expect stop

I am sorry if the if () { } is not real Go syntax; I am a C programmer haha (although the stuff inside the () and {} is real, I did a little research :).

Doing this last bit ensures that Upstart will wait until your application is set up correctly before firing off the started event. If no other jobs are waiting for your app, then you do not really need that.

You will need the --background flag if you want to use SysVinit and start-stop-daemon with Go programs.

I suggest using something like Supervisor or Circus instead.

Edit:

This is not strictly true, if your Go program daemonizes its self, the --background flag can be excluded.