PC Tips‎ > ‎

upstart

I wrote my first upstart script today, and I found it to be an extremely frustrating process due to unexpected inconsistencies compounded by deficient documentation.  Below is the upstart config I wrote for a Node.JS application.  It seems to work.  I documented my frustrations in the comments.  I decided to write this config because I had seen other configs online who tended to use things like sudo lines inside script blocks to reduce the permissions of the running application.  I didn't think that seemed very 'upstarty' and thought it could be done better.  I'm glad to have learned some upstart, but after this experience I'm absolutely not surprised I haven't done this before.

description "Insteon home control server using Node.JS"
author      "secesh"

# Don't typo anything.  If you say 'eng' instead of 'env', you'll get an error
# saying: "unknown job."  What you won't get is an error saying something like:
# "Failed to process job configuration file due to unrecognized token on line 15."
# Vague/misleading error comments only succeed at frustrating debuggers.
#
# I'm using system-wide node here, but you might prefer a localized compilation of node 
# to ensure version compatibility with the application (when running multiple applications).
env NODE=/usr/local/bin/node
env LOG=log/server.log

# upstart environment variables are limited and inconsistent.
# they are only accessible "to the jobs whose job configuration files they are defined in"
# This means they're only accessible to child scripts (exec stanzas and script blocks).
# They are not available within upstart.  They are not variables; they are environment variables.
# This means you can't do something like:
# env USER=matt
# env HOME=/home/$USER
######################

# I didn't do any testing on this, but figured these were the minimum prerequisites.
start on started mountall networking
stop on shutdown

respawn
# respawn limit [count] [timeout]
# This is the maximum respawn rate; if this rate is exceeded, the respawn attempts will stop.
# default is 10 5.  If there are more than 10 respawn attempts within 5 seconds, it will quit.

# setuid/setgid can not use env variables.
setuid matt
setgid matt

# See comment above regarding consistency of variables.  exec honors env variables; chdir does not.
# environment variables should consistently be handled like real variables within the context 
# of the upstart config file.
chdir /home/matt/Documents/node/server
exec $NODE server.js >> $LOG 2>&1

# Getting the PID can be problematic. Upstart knows what the PID is,
# but I cannot find documentation of a variable that references it properly.
# so you'll notice I don't track the PID; I left comments below to
# illustrate the problem. When this script starts the service, it logs
# the correct PID to the console. but PIDs grabbed below are not correct.
# Offering a variable like $PID that contains the PID upstart is using
# to monitor the service would be nice.

#script
# DO NOT UNCOMMENT THIS BLOCK. Because we're using the exec stanza above,
# Existence of a script stanza, even if empty, will cause upstart to fail to
# recognize which process is our service, causing it to crap after a respawn attempt.
# That's understandable, but the documentation regarding script blocks is woefully
# deficient.  see: http://upstart.ubuntu.com/cookbook/#script.  It offers barely one line
# to describe a core concept.  They put way more effort into explaining setgid, which
# covers an immensely narrower topic.  I know there's more documentation elsewhere, but
# the cookbook should at least link to the other documentation while making an effort 
# to explain the concept.  Especially because the wiki says: see the cookbook.
#end script
post-start script
    # Tracking $$ here results in a PID greater than the actual PID
    # echo $$ >> run/server.pid
end script
pre-start script
    # Date format same as (new Date()).toISOString() for consistency
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] Starting" >> $LOG
    # Tracking $$ here results in a PID less than the actual PID
    # echo $$ > run/server.pid
end script
pre-stop script
    # rm run/server.pid
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] Stopping" >> $LOG
end script
Comments