zapty / forever-service

Provision node script as a service via forever, allowing it to automatically start on boot, working across various Linux distros and OS
https://github.com/zapty/forever-service
MIT License
594 stars 65 forks source link

passing forever-service script options causing the script to fail #36

Closed corzand closed 9 years ago

corzand commented 9 years ago

Hello everyone, I'm struggling with a quite idiot problem, but i can't figure out how to solving.

Basically, I use to run a forever script passing options after the script name, and everything is working fine: forever start c9/sdk/server.js -p 8181 -l 0.0.0.0 -a : -w io-at-spot/io-at-spot

But when, with forever-service install instruction, i wrap these options in a string after -o, the script fails with error: 'Arguments to path.join must be strings'.

sudo forever-service install cloud9 --script c9/sdk/server.js -o " -p 8181 -l 0.0.0.0 -a : -w io-at-spot/io-at-spot"

Any suggestions? Looks so strange

arvind-agarwal commented 9 years ago

@corzand sorry for late response on this. So are you getting the error while staring the service or provisioning it? Can you paste exact commands and outputs.

corzand commented 9 years ago

@arvind-agarwal Sorry for delay too!

When i create the service, everything looks ok

pi@raspberrypi-andrea ~ $ sudo forever-service install cloud9 --script c9/sdk/server.js -o " -p 818
1 -l 0.0.0.0 -a : -w io-at-spot/io-at-spot"
forever-service version 0.5.2

Platform - Raspbian GNU/Linux 7 (wheezy)
update-rc.d: using dependency based boot sequencing
insserv: Script bluetoothd is broken: incomplete LSB comment.
insserv: missing valid name for `Provides:' please add.
cloud9 provisioned successfully

Commands to interact with service cloud9
Start   - "sudo service cloud9 start"
Stop    - "sudo service cloud9 stop"
Status  - "sudo service cloud9 status"
Restart - "sudo service cloud9 restart"

But when i start the service, it's not giving particular error messages, but fails silently.

pi@raspberrypi-andrea ~ $ sudo service cloud9 start
Starting cloud9
pi@raspberrypi-andrea ~ $

This is what the service log tells me:

Starting standalone
path.js:488
      throw new TypeError('Arguments to path.join must be strings');
            ^
TypeError: Arguments to path.join must be strings
    at Object.posix.join (path.js:488:13)
    at module.exports (/home/pi/c9/sdk/settings/standalone.js:27:28)
    at start (/home/pi/c9/sdk/server.js:126:77)
    at /home/pi/c9/sdk/server.js:93:13
    at /home/pi/c9/sdk/node_modules/async/lib/async.js:122:13
    at _each (/home/pi/c9/sdk/node_modules/async/lib/async.js:46:13)
    at Object.async.each (/home/pi/c9/sdk/node_modules/async/lib/async.js:121:9)
    at startConfigs (/home/pi/c9/sdk/server.js:90:15)
    at main (/home/pi/c9/sdk/server.js:85:5)
    at main (/home/pi/c9/sdk/server.js:78:16)
error: Forever detected script exited with code: 1
error: Script restart attempt #1
Starting standalone
path.js:488
      throw new TypeError('Arguments to path.join must be strings');

Looks like the service is not passing arguments in the right way... what is going wrong?

arvind-agarwal commented 9 years ago

Please paste /etc/init.d/cloud9 contents to investigate

corzand commented 9 years ago
pi@raspberrypi-andrea /etc/init.d $ cat cloud9
#!/bin/bash

### BEGIN INIT INFO
# Provides: cloud9
# Required-Start:    $network $remote_fs $local_fs
# Required-Stop:     $network $remote_fs $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: forever-service startup script for cloud9
# Description: forever-service startup script for node script based service cloud9, uses forever to
start the service
### END INIT INFO

#       CLI node /usr/local/bin/forever-service install cloud9 --script c9/sdk/server.js -o  -p 8181
 -l 0.0.0.0 -a : -w io-at-spot/io-at-spot
#       Working Directory /home/pi

#Setup Environment variables (if any)

# Check if any of $pid (could be plural) are running
LOGFILE="/var/log/cloud9.log"

LOCKFILE="/var/lock/cloud9"

# introduce some gaps between restarts and throttle continous restarts
MIN_UPTIME="5000"
SPIN_SLEEP_TIME="2000"

# kill signal: Since default needs to be SIGTERM, it is important that services gracefully shutdown,

# specially if they are doing transactions or other work which should not be interuppted in between
# for exceptional situation where you dont care about abrupt shutdown, SIGKILL should be used
KILL_SIGNAL="SIGTERM"

# Wait time afer with SIGKILL will be sent to the process, in case SIGTERM is not fully finished
# This is required since when we use SIGTERM, some times if there is problem in code, it might take
lot of time for process to exit
# or process may never exit, in such siutation we have to forcebly kill it so that shutdown or servi
ce restart can be done appropriately
# this wait time is in millisecond
KILLWAITTIME=5000

killtree() {
    local _pid=$1
    local _sig=${2:--TERM}
    kill -stop ${_pid} # needed to stop quickly forking parent from producing children between child
 killing and parent killing
    for _child in $(ps -o pid --no-headers --ppid ${_pid}); do
        killtree ${_child} ${_sig}
    done
    kill -${_sig} ${_pid}
}

checkpidexists() {
        [ -d "/proc/$1" ] && return 0
        return 1
}

start() {
        #this is to ensure forever is able to find out the correct root every time
        export FOREVER_ROOT=/root/.forever

        STATUS=$(/usr/local/bin/forever --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\(cloud9\)\s.*\
)/\2-status:\1/;tx;d;:x')

        if ! [ -z "$STATUS" ]; then
                echo "Service cloud9 already running"
                return 0
        fi

        echo  "Starting cloud9"

        # move to the directory from where the inital forever script was launched so that even if it
 is relative it works as expected
        cd /home/pi

        /usr/local/bin/forever \
        -a \
        -l $LOGFILE \
        --minUptime $MIN_UPTIME \
        --spinSleepTime $SPIN_SLEEP_TIME \
        --killSignal $KILL_SIGNAL \
         \
        --uid cloud9 \
        start c9/sdk/server.js -p 8181 -l 0.0.0.0 -a : -w io-at-spot/io-at-spot 2>&1 >/dev/null

        RETVAL=$?

        [ $RETVAL = 0 ] && touch $LOCKFILE
        return $RETVAL
}

stop() {
        #this is to ensure forever is able to find out the correct root every time
        export FOREVER_ROOT=/root/.forever

        echo -n "Shutting down cloud9: "

        STATUS=$(/usr/local/bin/forever --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\(cloud9\)\s.*\
)/\2-status:\1/;tx;d;:x')

        if [ -z "$STATUS" ]; then
                echo "Not running"
                return 0
        fi

        # PID=$(<$PIDFILE) - Changed to detection based on actual PID from forever, sicne due to wat
chDirectory pid could dynamically change

        PID=$(/usr/local/bin/forever --plain list | sed -n -e '/data:\s*\[[0-9]*\]\s\(cloud9\)\s/p'
| awk '{print $7}')

        if [ -z "$PID" ]; then
                echo "Could not get pid"
                return 0
        fi

        #run in background, since recent changes in forever, now blocks stop call with SIGTERM is fi
nished
        #but we want to wait till some time and forcibly kill after elapsed time
        #without background script, we could be waiting forever

        /usr/local/bin/forever stop cloud9 2>&1 >/dev/null &

        CURRENTWAITTIME=$KILLWAITTIME
        # wait for some time before forcefully killing the process
        while [ $CURRENTWAITTIME -gt 0 ]; do
                #check if the process is still running
                checkpidexists $PID
                if [ $? -ne 0 ]; then
                        # if not running we can break, since no more wait is needed, service is stop
ped
                        echo "Successful"
                        break
                fi

                sleep 1
                CURRENTWAITTIME=$(( $CURRENTWAITTIME - 1000))

        done
        checkpidexists $PID
        if [  $? -eq 0  ]; then
                killtree $PID 9
                echo 'Forced shutdown'
        fi

        rm -f $PIDFILE 2>&1 >/dev/null
        rm -f $LOCKFILE 2>&1 >/dev/null
        return 0

}

status() {
        #this is to ensure forever is able to find out the correct root every time
        export FOREVER_ROOT=/root/.forever

        STATUS=$(/usr/local/bin/forever --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\(cloud9\)\s.*\
)/\2-status:\1/;tx;d;:x')

        if [ -z "$STATUS" ]; then
                echo "cloud9 is not running"
                RETVAL=3
        else
                echo $STATUS
                RETVAL=0
        fi
        return $RETVAL
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    status)
        status
        ;;
    restart)
        stop
        start
        ;;
    *)
        echo "Usage: <servicename> {start|stop|status|restart}"
        exit 1
        ;;
esac
exit $?
arvind-agarwal commented 9 years ago

I dont see any issues in the way service is provisioned. If you notice,

/usr/local/bin/forever \
        -a \
        -l $LOGFILE \
        --minUptime $MIN_UPTIME \
        --spinSleepTime $SPIN_SLEEP_TIME \
        --killSignal $KILL_SIGNAL \
         \
        --uid cloud9 \
       start c9/sdk/server.js -p 8181 -l 0.0.0.0 -a : -w io-at-spot/io-at-spot 2>&1 >/dev/null

This seems to be exactly the way you are passing the arguments. I guess you will have to debug your app, some times it could be also related to file permissions, also here the home directory for service will be root since service is run under root privileges.

arvind-agarwal commented 9 years ago

@corzand please update the issue, if you need further help or close the issue if you have found the solution. (And share the solution if you have found..)

corzand commented 9 years ago

Actually I cannot figure out why if i run the forever command alone (with or without sudo):

forever start c9/sdk/server.js -p 8181 -l 0.0.0.0 -a : -w io-at-spot/io-at-spot >/dev/null

everything is working fine, while running the forever-service created script (that contains the same lines of code) results in errors into the log.

I don't know how to fix it, looks like bash is passing the parameters differently in the two cases...

arvind-agarwal commented 9 years ago

Only thing i can suspect is the HOME directory might be pointing differently when running as service, so debug your logic to check if you are using HOME directory anywhere..

corzand commented 9 years ago

You're right. Using forever-service, "process.env.HOME" variable is undefined, while when running the script with forever, "process.env.HOME" has the value "/home/pi".

Is this behaviour normal? In this case, I will patch it somehow.

corzand commented 9 years ago

fixed it using -e param and setting HOME=/home/pi.

Thanks for help