Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 129 lines (115 sloc) 3.896 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
fs = require 'fs'
daemon = require 'daemon'

exports.printStatus = (st) ->
    if st.pid
        console.log 'Process running with pid %d.', st.pid
        process.exit 0

    else if st.exists
        console.log 'Pidfile exists, but process is dead.'
        process.exit 1
    else
        console.log 'Not running.'
        process.exit 3

exports.status = (pidfile, cb = exports.printStatus) ->
    fs.readFile pidfile, 'utf8', (err, data) ->
        if err
            cb exists: err.code isnt 'ENOENT'
        else if match = /^\d+/.exec(data)
            pid = parseInt match[0]
            try
                process.kill pid, 0
                cb pid: pid
            catch e
                cb exists: true
        else
            cb exists: true

exports.startSucceeded = (pid) ->
    if pid
        console.log 'Process already running with pid %d.', pid
    else
        console.log 'Started.'

exports.startFailed = (err) ->
    console.log err
    process.exit 1

# This can fail if the pidfile becomes unwriteable after status() but before
# daemon.lock(). It's a race condition, but it's a hard one to fix.
exports.start = ({ pidfile, logfile, run, success, failure }) ->
    success or= exports.startSucceeded
    failure or= exports.startFailed
    logfile or= '/dev/null'

    start = (err) ->
        return failure(err) if err
        fs.open logfile, 'a+', 0666, (err, fd) ->
            return failure(err) if err
            success()
            pid = daemon.start(fd)
            daemon.lock(pidfile)
            run()

    exports.status pidfile, (st) ->
        if st.pid
            success st.pid, true
        else if st.exists
            fs.unlink pidfile, start
        else
            start()

exports.stopped = (killed) ->
    if killed
        console.log 'Stopped.'
    else
        console.log 'Not running.'
    process.exit 0

exports.hardKiller = (timeout = 2000) ->
    (pid, cb) ->
        signals = ['TERM', 'INT', 'QUIT', 'KILL']
        tryKill = ->
            sig = "SIG#{ signals[0] }"
            try
                # throws when the process no longer exists
                process.kill pid, sig
                signals.shift() if signals.length > 1
                setTimeout (-> tryKill sig), timeout
            catch e
                cb(signals.length < 4)
        tryKill()

exports.softKiller = (timeout = 2000) ->
    (pid, cb) ->
        sig = "SIGTERM"
        tryKill = ->
            try
                # throws when the process no longer exists
                process.kill pid, sig
                console.log "Waiting for pid " + pid
                sig = 0 if sig != 0
                first = false
                setTimeout tryKill, timeout
            catch e
                cb(sig == 0)
        tryKill()

exports.stop = (pidfile, cb = exports.stopped, killer = exports.hardKiller(2000)) ->
    exports.status pidfile, ({pid}) ->
        if pid
            killer pid, (killed) ->
                fs.unlink pidfile, -> cb(killed)
        else
            cb false

exports.simple = ({pidfile, logfile, command, run, killer}) ->
    command or= process.argv[2]
    killer or= null
    start = -> exports.start { pidfile, logfile, run }
    switch command
        when 'start' then start()
        when 'stop' then exports.stop pidfile, null, killer
        when 'status' then exports.status pidfile
        when 'restart', 'force-reload'
            exports.stop pidfile, start, killer
        when 'try-restart'
            exports.stop pidfile, (killed) ->
                if killed
                    exports.start { pidfile, logfile, run }
                else
                    console.log 'Not running.'
                    process.exit 1
        else
            console.log 'Command must be one of: ' +
                'start|stop|status|restart|force-reload|try-restart'
            process.exit 1
Something went wrong with that request. Please try again.