public
Description: Supervised TCPServer, Yielding Listeners Easily
Homepage: http://code.jeremyevans.net/doc/ruby-style/
Clone URL: git://github.com/jeremyevans/ruby-style.git
ruby-style / README
100644 392 lines (299 sloc) 17.195 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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
= style (Supervised TCPServer, Yielding Listeners Easily)
 
style is a Ruby program that provides a supervised TCPServer (or TCPServers)
with multiple listening childing processes. It allows the child processes to
be killed and respawned while making sure that there are always child processes
available to listen to requests. It automatically respawns dead
child processes. It allows for increasing and decreasing the number of child
processes on the fly.
 
style is distributed as a gem, and can be installed with:
 
    sudo gem install ruby-style
 
Feedback/Bugs/Support Requests should be handled through RubyForge at
http://rubyforge.org/projects/ruby-style/.
 
The RDoc is available at http://ruby-style.rubyforge.org.
 
Source is available at github: http://github.com/jeremyevans/ruby-style
 
== Highlights
 
* Always has child listeners available, so no connections are lost when
  listeners are restarted
* Automatically restarts dead child processes
* Supports both single port and multiple port clustering, with an arbitrary
  number of listeners per port
* Supports increasing and decreasing the number of child processes per port on
  the fly
* Supports both command line and yaml config file configuration
* Is easily extensible to support running other frameworks and protocols other
  than the included ones (Rails; SCGI, Mongrel, Thin, and Evented Mongrel)
 
== Running and configuration
 
To see the available commands and possible and default configuration options,
just run the program without any arguments:
 
style [option value, ...] (decrement|halt|increment|restart|run|start|stop)
 Options:
  -a, --adapter Adapter/Framework to use [rails]
  -b, --bind IP address to bind to [127.0.0.1]
  -c, --config Location of config file [style.yaml]
  -d, --directory Working directory [.]
  -D, --debug Run the program in the foreground without forking [No]
  -f, --fork Number of listners on each port [1]
  -h, --handler Handler/Server to use [mongrel]
  -k, --killtime Number of seconds to wait when killing each child [2]
  -l, --logfile Where to redirect STDOUT and STDERR [style.log]
  -n, --number Number of ports to which to bind [1]
  -p, --port Starting port to which to bind [9999]
  -P, --pidfile Location of pid file [style.pid]
  -u, --unsupervised Whether to run unsupervised [No]
 
Here's what the various commands do:
 
* decrement (USR2) - Decrease the number of listeners per port by 1
* halt (TERM) - Immediately shutdown the child processes and exit
* increment (USR1) - Increase the number of listeners per port by 1
* restart (HUP) - Replace the current listeners with new listeners
* run - Runs the supervisor and listening processes without detaching
* start - Starts the supervisor process and the listening processes
* stop (INT) - Gracefully shutdown the child processes and exit
 
All commands except start and run just send the listed signal to the
preexisting supervisor process specified in the pid file.
 
The signals can be sent directly to style when started with the run command,
which is the natural way to use style with runit or daemontools.
 
Note that the -d (--directory) option changes the working directory of the
process, so the -c, -l, and -P options are relative to that.
 
Here's a longer explanation of the options:
 
  -a, --adapter Adapter/Framework to use [rails]
 
  This is the adapter/framework to use. Support for Rails is
  included in the distribution, and is special-cased. Any other value runs
  require with the argument given.
 
  -b, --bind IP address to bind to [127.0.0.1]
 
  This is the TCP/IP networking socket to bind to. It defaults to the
  loopback address because generally the web application runs on the same
  physical server as the web server. If this is not the case, change it to an
  externally available IP, and make sure to lock down access to the port via a
  firewall.
 
  -c, --config Location of config file [config/style.yaml]
 
  This is the configuration file for style. It is recommended that you use
  this instead of the command line configuration, as it saves typing. This
  path is relative to the working directory, so if it is not inside the working
  directory, make sure you specify an absolute path. This option is not
  configurable from the configuration file.
 
  -d, --directory Working directory [.]
 
  This is the working directory of the process. It should generally be the
  path to the root of the application. Alternatively, you can change to the
  root of the application before hand and then not use this option. This option
  is not configurable from the configuration file.
 
  -D, --debug Run the program in the foreground without forking [No]
 
  This runs the program in the program without forking, aiding in debugging a
  problematic configuration.
 
  -f, --fork Number of listners on each port [1]
 
  This enables multiple child processes listening on each port. It is
  recommended that you use -f instead of -n for multiple listeners, since it
  simplifies the configuration of the webserver, and can also eliminate
  the need for a proxy such as pound or pen to handle this for you. It
  defaults to one process per port. Note that when restarting processes,
  replacement processes are started before the currently listening processes
  are killed, so it is possibly to have multiple processes listening on a port
  even if this is left at one.
 
  -h, --handler Handler/Server to use [mongrel]
 
  This is the handler/server to use. Support for Mongrel, Evented Mongrel,
  and SCGI is included in the distribution. Support for other servers is
  easy to add as long as the servers can be modified to use the socket
  created by style ($STYLE_SOCKET).
 
  -k, --killtime Number of seconds to wait when killing each child [2]
 
  This sets the time that style between sending shutdown signals to child
  process, as well as the time between starting a replacement process and
  killing an existing process. When restarting, the amount of time spent
  waiting should be between 2-3 * (killtime * number * fork).
 
  -l, --logfile Where to redirect STDOUT and STDERR [log/style.log]
 
  This is the location of the log file, relative to the working directory.
  style itself doesn't output anything after it has detached from the listening
  terminal, but child listening processes might output to STDOUT or STDERR.
 
  -n, --number Number of ports to which to bind [1]
 
  This makes style start up multiple sockets, one per port starting with the
  given port (so port, port+1, port+2, ..., port+n). This makes webserver
  configuration a little more difficult than with just using -f, and might
  also require a separate proxy such as pound or pen, so you should try just
  using -f first.
  
  -p, --port Starting port to which to bind [9999]
 
  This is the starting (or only) port that style will use. If -n is used, all
  ports will be greater than this one.
 
  -P, --pidfile Location of pid file [log/style.pid]
 
  This is the pid file, relative to the working directory. The pid file is
  necessary, as it is what is used by all commands other than start. If
  incorrect information is in the pid file, the processes won't be stopped when
  they should be, and you will probably won't be able to start new processes
  (because the ports will still be in use).
 
  -u, --unsupervised Whether to run unsupervised [No]
  
  This starts child processes without using a supervisor process. It is not
  as reliable or as featureful as the regular supervised mode, but those may
  not be necessary for smaller sites. In unsupervised mode, only restart,
  start, and stop are valid commands, child processes aren't automatically
  restarted when they die, and you may lose connections during restarts.
 
Every one of the long options can also be specified in the config file. Also,
the config file must be used if you want to specify any settings specific to
adapter being used (such as modifying the Rails environment setting). See
below for information on the adapter_config config file variable.
 
== The config file
 
Example Rails+Mongrel style.yaml that listens on ports 8912 and 8193 on any
interface, with three listeners per port. Note how the :adapter_config entry
is used to set up settings specific to the Rails adapter, such as placing
Rails in development mode. Ignore the pipes at the beginning of the line,
blame RDoc limitations.
 
 | ---
 | :port: 8912
 | :bind: ""
 | :fork: 3
 | :number: 2
 | :killtime: 1
 | :adapter: rails
 | :handler: mongrel
 | :adapter_config:
 | :environment: development
 | :log_file: log/rails-mongrel.log
 | :docroot: public
 | :num_processors: 99
 | :timeout: 100
 
Example Rails+SCGI style.yaml that has four listeners on port 8912:
 
 | ---
 | :port: 8912
 | :fork: 4
 | :number: 1
 | :adapter: rails
 | :handler: scgi
 | :adapter_config:
 | :logfile: log/railsscgi.log
 | :maxconns: 10
 | :environment: production
 
Configuration for running Rails with Thin on ports 3456-3459 with one
listener on each port:
 
 | ---
 | :port: 3456
 | :number: 4
 | :adapter: rails
 | :handler: thin
 
Very simple configuration that runs Ramaze (with the default start.rb runner)
+Evented Mongrel in unsupervised mode on port 3000.
 
 | ---
 | :port: 3000
 | :unsupervised: 1
 | :adapter: start
 | :handler: evented_mongrel
 
Using the generic adapter to host a camping application (you are responsible
for having the camping application in a my_camping_app.rb file in your
$LOAD_PATH that uses Mongrel to run camping):
 
 | ---
 | :port: 3301
 | :adapter: my_camping_app
 | :environment:
 | RACK_ENV: production
 
One important thing to note from the example above is that you can specify
an :environment key in the config file that should be a hash. If it is
provided, the hash under it will be added to the environment before
the child processes are loaded.
 
== How restarting works
 
Restarting works by starting a new child process, waiting for killtime, and then
killing the exisiting process. It repeats this for all existing child processes.
 
For example:
 
  # style idling with three listeners
  Thu Sep 6 12:01:47 PDT 2007
  11460 ?? I 0:00.00 ruby: RailsMongrelStyle dir:/home/billg/testrails supervisor (ruby)
   6540 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
    272 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
  27808 ?? I 0:02.51 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
  # Restart occurs, new process started (1207)
  Thu Sep 6 12:01:49 PDT 2007
  11460 ?? I 0:00.00 ruby: RailsMongrelStyle dir:/home/billg/testrails supervisor (ruby)
  27808 ?? I 0:02.51 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
    272 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   6540 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   1207 ?? R 0:00.95 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
  # Old process killed (27808)
  Thu Sep 6 12:01:51 PDT 2007
  11460 ?? I 0:00.01 ruby: RailsMongrelStyle dir:/home/billg/testrails supervisor (ruby)
   6540 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
    272 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   1207 ?? I 0:02.51 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
  # New process started (3204)
  Thu Sep 6 12:01:53 PDT 2007
  11460 ?? I 0:00.01 ruby: RailsMongrelStyle dir:/home/billg/testrails supervisor (ruby)
    272 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   6540 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   1207 ?? I 0:02.51 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   3204 ?? R 0:01.01 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
  # Old process killed (6540)
  Thu Sep 6 12:01:55 PDT 2007
  11460 ?? I 0:00.01 ruby: RailsMongrelStyle dir:/home/billg/testrails supervisor (ruby)
    272 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   1207 ?? I 0:02.51 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   3204 ?? I 0:02.49 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
  # New process started (6766)
  Thu Sep 6 12:01:57 PDT 2007
  11460 ?? I 0:00.01 ruby: RailsMongrelStyle dir:/home/billg/testrails supervisor (ruby)
    272 ?? I 0:02.52 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   1207 ?? I 0:02.51 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   3204 ?? I 0:02.49 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   6766 ?? R 0:00.99 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
  # Old process killed (272)
  Thu Sep 6 12:01:59 PDT 2007
  11460 ?? I 0:00.01 ruby: RailsMongrelStyle dir:/home/billg/testrails supervisor (ruby)
   1207 ?? I 0:02.51 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   3204 ?? I 0:02.49 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
   6766 ?? I 0:02.49 ruby: RailsMongrelStyle dir:/home/billg/testrails port:8912 environment:production (ruby)
 
Result, three brand new listening processes, total time to restart is about 12
seconds (2 * (2 killtime * 1 number * 3 fork)).
 
== Other handlers
 
To add support for another handler, make sure the instead of creating a socket,
it uses the socket provided by style, available in the global variable
$STYLE_SOCKET. See existing handler code to see how Mongrel, SCGI, and Event
Machine were modified to support this.
 
Style loads handlers from style/handler relative to the load path, so you can
add your own handlers without modifying the program, as long as you place the
files somewhere in the load path.
 
== Changes to the default config, logfile, and pidfile in 1.2.0
 
Previously, style had the following defaults:
 
* config - config/style.yaml
* logfile - log/style.log
* pidfile - log/style.pid
 
These made sense because style was originally designed to serve Rails
applications, which all have config and log directories. Now that style
serves more types of applications, and few of those have config or log
directories, these no longer made good defaults. The new defaults use the
same filename, without the directory:
 
* config - style.yaml
* logfile - style.log
* pidfile - style.pid
 
== Changes to adapter handling in 1.2.0
 
Adapter handling was simplified in 1.2.0. Because there is no easy script
that loads rails, there is still a rails adapter. However, for all other
frameworks you would want to use, just specify the file you want to require
as the adapter. This simplifies things and allows you to specify your
adapter file on the command line:
 
  style -a sinatra_runner start
 
Before, this wasn't possible, you had to set up a configuration file or put
the adapter file you wanted to use in a style/adapter subdirectory in the load
path.
 
== Upgrading from 1.1.*, previously using ramaze adapter
 
Previously, if you used the following configuration:
 
 | ---
 | :adapter: ramaze
 
You should change it to:
 
 | ---
 | :adapter: start
 
If you specified your own :runner via :adapter_config, just use that runner
name for the :adapter instead of start.
 
The Ramaze adapter had some default settings that you might want to consider:
 
  :test_connections=>false, :force=>true
 
You should make sure your ramaze runner sets the correct :adapter for Ramaze to
use (it should use the same one as style uses). Having it set the :host and
:port are good ideas, otherwise it may display those incorrectly. You should
make sure your ramaze runner actually calls Ramaze.start, as well.
 
== Upgrading from 1.1.*, previously using generic adapter
 
If you were previously using the generic adapter, the upgrade is simple. Change
the following cofiguration from:
 
 | ---
 | :adapter: generic
 | :adapter_config:
 | :script: cse
 
To:
 
 | ---
 | :adapter: cse
 
== FAQ
 
Q: Does this run on Windows?
 
A: Only using debug mode (--debug, -D). All other modes use fork, which isn't
   supported on Windows.
 
Q: Does it work with Capistrano yet?
 
A: I haven't tried. It probably can, but it will take a little custom work.