@@ -11,14 +11,81 @@ var sys = require('sys'),
11
11
eyes = require ( 'eyes' ) ,
12
12
path = require ( 'path' ) ,
13
13
events = require ( 'events' ) ,
14
- spawn = require ( 'child_process' ) . spawn ;
14
+ spawn = require ( 'child_process' ) . spawn ,
15
+ daemon = require ( 'daemon' ) ;
16
+
17
+ var config ,
18
+ forever = exports ;
19
+
20
+ forever . load = function ( options , callback ) {
21
+ options . root = options . root || path . join ( '/tmp' , 'forever' ) ,
22
+ options . pidPath = options . pidPath || path . join ( options . root , 'pids' ) ;
23
+ config = options ;
24
+
25
+ // Create the two directories, ignoring errors
26
+ fs . mkdir ( config . root , 0755 , function ( err ) {
27
+ fs . mkdir ( config . pidPath , 0755 , function ( err2 ) {
28
+ callback ( ) ;
29
+ } ) ;
30
+ } ) ;
31
+ } ;
32
+
33
+ // Export the core 'start' method
34
+ forever . start = function ( file , options ) {
35
+ return new Forever ( file , options ) . start ( ) ;
36
+ } ;
37
+
38
+ forever . startDaemon = function ( file , options ) {
39
+ options . logfile = options . logfile || 'forever.log' ;
40
+ options . logfile = path . join ( config . root , options . logfile ) ;
41
+ var runner = new Forever ( file , options ) ;
42
+
43
+ fs . open ( options . logfile , 'w+' , function ( err , fd ) {
44
+ try {
45
+ daemon . start ( fd ) ;
46
+ daemon . lock ( path . join ( config . root , options . pidFile ) ) ;
47
+ runner . start ( ) . save ( ) ;
48
+ }
49
+ catch ( ex ) {
50
+ // Ignore errors
51
+ }
52
+ } ) ;
53
+ } ;
54
+
55
+ forever . stop = function ( file , options ) {
56
+ return new Forever ( file , options ) . stop ( ) ;
57
+ } ;
58
+
59
+ //
60
+ // function randomString (bits)
61
+ // randomString returns a pseude-random ASCII string which contains at least the specified number of bits of entropy
62
+ // the return value is a string of length ⌈bits/6⌉ of characters from the base64 alphabet
63
+ //
64
+ forever . randomString = function ( bits ) {
65
+ var chars , rand , i , ret ;
66
+ chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' ;
67
+ ret = '' ;
68
+
69
+ //
70
+ // in v8, Math.random() yields 32 pseudo-random bits (in spidermonkey it gives 53)
71
+ //
72
+ while ( bits > 0 ) {
73
+ rand = Math . floor ( Math . random ( ) * 0x100000000 ) // 32-bit integer
74
+ // base 64 means 6 bits per character, so we use the top 30 bits from rand to give 30/6=5 characters.
75
+ for ( i = 26 ; i > 0 && bits > 0 ; i -= 6 , bits -= 6 ) {
76
+ ret += chars [ 0x3F & rand >>> i ] ;
77
+ }
78
+ }
79
+ return ret ;
80
+ } ;
15
81
16
82
var Forever = function ( file , options ) {
17
83
events . EventEmitter . call ( this ) ;
18
84
19
85
options . options . unshift ( file ) ;
20
86
options . silent = options . silent || false ;
21
87
options . forever = options . forever || false ;
88
+ options . logout = typeof options . logfile !== 'undefined' ;
22
89
options . stdout = typeof options . outfile !== 'undefined' ;
23
90
options . stderr = typeof options . errfile !== 'undefined' ;
24
91
@@ -38,15 +105,18 @@ var Forever = function (file, options) {
38
105
39
106
sys . inherits ( Forever , events . EventEmitter ) ;
40
107
41
- Forever . prototype . run = function ( ) {
108
+ Forever . prototype . start = function ( ) {
42
109
var self = this , child = spawn ( 'node' , this . options . options ) ;
110
+
43
111
this . child = child ;
112
+ this . running = true ;
44
113
45
114
// Hook all stream data and process it
46
115
function listenTo ( stream ) {
47
116
child [ stream ] . on ( 'data' , function ( data ) {
48
- // If we haven't been silenced, write to the process stdout stream
49
- if ( ! self . options . silent ) {
117
+ // If we haven't been silenced, and we don't have a file stream
118
+ // to output to write to the process stdout stream
119
+ if ( ! self . options . silent && ! self . options [ stream ] ) {
50
120
process . stdout . write ( data ) ;
51
121
}
52
122
@@ -55,23 +125,28 @@ Forever.prototype.run = function () {
55
125
self [ stream ] . write ( data ) ;
56
126
}
57
127
58
- self . emit ( stream , null , data ) ;
128
+ self . emit ( stream , data ) ;
59
129
} ) ;
60
130
}
61
131
62
132
// Listen to stdout and stderr
63
133
listenTo ( 'stdout' ) ;
64
134
listenTo ( 'stderr' ) ;
65
-
135
+
66
136
child . on ( 'exit' , function ( code ) {
137
+ self . log ( 'Forever detected script exited with code: ' + code ) ;
67
138
self . times ++ ;
139
+
68
140
if ( self . options . forever || self . times < self . options . max ) {
69
141
self . emit ( 'restart' , null , self ) ;
70
142
process . nextTick ( function ( ) {
71
- self . run ( ) ;
143
+ self . log ( 'Forever restarting script for ' + self . times + ' time' ) ;
144
+ self . start ( ) ;
72
145
} ) ;
73
146
}
74
147
else {
148
+ this . running = false ;
149
+
75
150
// If had to write to an stdout file, close it
76
151
if ( self . options . stdout ) {
77
152
self . stdout . end ( ) ;
@@ -90,10 +165,44 @@ Forever.prototype.run = function () {
90
165
return this ;
91
166
} ;
92
167
93
- // Export the Forever object
94
- exports . Forever = Forever ;
168
+ Forever . prototype . save = function ( ) {
169
+ var self = this ;
170
+ if ( ! this . running ) {
171
+ process . nextTick ( function ( ) {
172
+ self . emit ( 'error' , new Error ( 'Cannot save Forever instance that is not running' ) ) ;
173
+ } ) ;
174
+ }
175
+
176
+ var childData = {
177
+ pid : this . child . pid ,
178
+ foreverPid : process . pid ,
179
+ options : this . options . options . slice ( 1 ) ,
180
+ file : this . options . options [ 0 ]
181
+ } ;
182
+
183
+ var childPath = path . join ( config . pidPath , childData . pid + '.pid' ) ;
184
+ fs . writeFile ( childPath , JSON . stringify ( childData ) , function ( err ) {
185
+ // Ignore errors
186
+ } ) ;
187
+
188
+ // Chaining support
189
+ return this ;
190
+ } ;
191
+
192
+ Forever . prototype . log = function ( message ) {
193
+ if ( ! this . options . silent ) {
194
+ sys . puts ( message ) ;
195
+ }
196
+ }
95
197
96
- // Export the core 'run' method
97
- exports . run = function ( file , options ) {
98
- return new Forever ( file , options ) . run ( ) ;
198
+ Forever . prototype . stop = function ( ) {
199
+ //
200
+ // Remark: This is not implemented in 0.2.1
201
+ //
202
+
203
+ // Chaining support
204
+ return this ;
99
205
} ;
206
+
207
+ // Export the Forever object
208
+ forever . Forever = Forever ;
0 commit comments