Node.jsをforeverモジュールでデーモン化する

foreverモジュールを使用した時のメモです。


2年前くらいのネタです。

Node.jsはシングルスレッドのため、
エラー発生時にハンドリングされていないと止まってしまいます。

foreverを使用してデーモン化することで
エラー発生時に自動起動することができます。

github.com


インストー

npmでインストールします。

依存関係確認。

# npm view forever dependencies

{ cliff: '~0.1.9',
  clone: '^1.0.2',
  colors: '~0.6.2',
  flatiron: '~0.4.2',
  'forever-monitor': '~1.6.0',
  nconf: '~0.6.9',
  nssocket: '~0.5.1',
  'object-assign': '^3.0.0',
  optimist: '~0.6.0',
  'path-is-absolute': '~1.0.0',
  prettyjson: '^1.1.2',
  shush: '^1.0.0',
  timespan: '~2.3.0',
  utile: '~0.2.1',
  winston: '~0.8.1' }

インストール。
npm installで-gオプションを指定した場合はグローバルインストールとなり、
どこからでもコマンドが呼び出せるようになります。

# npm install -g forever

確認

# ll /usr/local/nodejs/lib/node_modules/
合計 8
drwxr-xr-x. 6 nobody root 4096  118 01:28 forever
drwxr-xr-x. 9 root   root 4096  118 00:13 npm

# which forever
/usr/local/nodejs/bin/forever
起動、停止

起動はforever startでモジュールを指定するだけ。

# forever start test.js
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: test.js

forever listで状態確認ができます。

# forever list
info:    Forever processes running
data:        uid  command                    script  forever pid   id logfile                 uptime
data:    [0] ugJf /usr/local/nodejs/bin/node test.js 75127   75132    /root/.forever/ugJf.log 0:0:0:9.317

停止は複数の方法があります。
forever listで表示されるインデックスを指定します。
上記の場合は[0]がインデックスになります。

# forever stop 0
info:    Forever stopped process:
    uid  command                    script  forever pid   id logfile                 uptime
[0] ugJf /usr/local/nodejs/bin/node test.js 75127   75132    /root/.forever/ugJf.log 0:0:0:32.77

もしくはuidを指定します。

# forever stop ugJf

もしくはpidを指定。

# forever stop 75132

もしくはモジュール名を指定。

# forever stop test.js

確認してみると止まっています。

# forever list
info:    No forever processes running
自動起動確認

こんなjsを用意します。
アクセスすると、dummy()メソッドが見つからず異常終了します。

test.js

var http = require('http');

http.createServer((req, res) => {
	res.writeHead(200, { 'Content-Type': 'text/plain' });
	res.end('Hello forever\n');
	dummy();
}).listen(8090, '127.0.0.1');

普通に起動してみます。

# node test.js

アクセスしてみると

# telnet localhost 8090
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.1 200 OK
Content-Type: text/plain
Date: Sun, 17 Jan 2016 17:20:31 GMT
Connection: close

Hello forever
Connection closed by foreign host.

エラーを出力して異常終了します。

/opt/node/test.js:7
        dummy();
        ^

ReferenceError: dummy is not defined
    at Server.<anonymous> (/opt/node/test.js:7:2)
    at emitTwo (events.js:87:13)
    at Server.emit (events.js:172:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:528:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)


次にforeverで起動してみます。

# forever start test.js
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: test.js

起動を確認。

# forever list
info:    Forever processes running
data:        uid  command                    script  forever pid   id logfile                 uptime
data:    [0] 5atb /usr/local/nodejs/bin/node test.js 76055   76060    /root/.forever/5atb.log 0:0:0:3.190

さっきと同じようにアクセスしてみます。

# telnet localhost 8090

確認してみると落ちずに起動しています。
pidが新しくなっているのがわかります。

# forever list
info:    Forever processes running
data:        uid  command                    script  forever pid   id logfile                 uptime
data:    [0] 5atb /usr/local/nodejs/bin/node test.js 76055   76071    /root/.forever/5atb.log 0:0:0:2.624

foreverのログを確認してみると、発生したエラーを確認できます。

# cat /root/.forever/5atb.log
/opt/node/test.js:7
        dummy();
        ^

ReferenceError: dummy is not defined
    at Server.<anonymous> (/opt/node/test.js:7:2)
    at emitTwo (events.js:87:13)
    at Server.emit (events.js:172:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:528:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
error: Forever detected script exited with code: 1
error: Script restart attempt #1

-mオプションで起動回数を指定できます。
回数には最初の起動も含まれるので、
-m 3の場合、自動起動は2回されます。

# forever start -m 3 test.js
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: test.js

アクセス1回目。

# telnet localhost 8090

ログを確認。エラーが発生しています。

# cat /root/.forever/gH8N.log
/opt/node/test.js:7
        dummy();
        ^

ReferenceError: dummy is not defined
    at Server.<anonymous> (/opt/node/test.js:7:2)
    at emitTwo (events.js:87:13)
    at Server.emit (events.js:172:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:528:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
error: Forever detected script exited with code: 1
error: Script restart attempt #1

自動起動により起動しています。

# forever list
info:    Forever processes running
data:        uid  command                    script  forever pid   id logfile                 uptime
data:    [0] gH8N /usr/local/nodejs/bin/node test.js 76227   76247    /root/.forever/gH8N.log 0:0:0:1.929

アクセス2回目。

# telnet localhost 8090

ログを確認。エラーが2回発生しています。

# cat /root/.forever/gH8N.log
/opt/node/test.js:7
        dummy();
        ^

ReferenceError: dummy is not defined
    at Server.<anonymous> (/opt/node/test.js:7:2)
    at emitTwo (events.js:87:13)
    at Server.emit (events.js:172:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:528:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
error: Forever detected script exited with code: 1
error: Script restart attempt #1
/opt/node/test.js:7
        dummy();
        ^

ReferenceError: dummy is not defined
    at Server.<anonymous> (/opt/node/test.js:7:2)
    at emitTwo (events.js:87:13)
    at Server.emit (events.js:172:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:528:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
error: Forever detected script exited with code: 1
error: Script restart attempt #2

自動起動により起動しています。

# forever list
info:    Forever processes running
data:        uid  command                    script  forever pid   id logfile                 uptime
data:    [0] gH8N /usr/local/nodejs/bin/node test.js 76227   76259    /root/.forever/gH8N.log 0:0:0:2.150

アクセス3回目。

# telnet localhost 8090

ログを確認。エラーが3回発生しています。

# cat /root/.forever/gH8N.log
/opt/node/test.js:7
        dummy();
        ^
ReferenceError: dummy is not defined
    at Server.<anonymous> (/opt/node/test.js:7:2)
    at emitTwo (events.js:87:13)
    at Server.emit (events.js:172:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:528:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
error: Forever detected script exited with code: 1
error: Script restart attempt #1
/opt/node/test.js:7
        dummy();
        ^

ReferenceError: dummy is not defined
    at Server.<anonymous> (/opt/node/test.js:7:2)
    at emitTwo (events.js:87:13)
    at Server.emit (events.js:172:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:528:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
error: Forever detected script exited with code: 1
error: Script restart attempt #2
/opt/node/test.js:7
        dummy();
        ^

ReferenceError: dummy is not defined
    at Server.<anonymous> (/opt/node/test.js:7:2)
    at emitTwo (events.js:87:13)
    at Server.emit (events.js:172:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:528:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
error: Forever detected script exited with code: 1


確認するとSTOPPEDに変わりました。
自動起動せずに停止しています。

# forever list
info:    Forever processes running
data:        uid  command                    script  forever pid   id logfile                 uptime
data:    [0] gH8N /usr/local/nodejs/bin/node test.js 76227   76259    /root/.forever/gH8N.log STOPPED


起動していないのでアクセスできません。

# telnet localhost 8090
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused


終わり。