Skip to content
Supervised TCPServer, Yielding Listeners Easily :: Unmaintained, switch to Unicorn or Rainbows! http://code.jeremyevans.net/doc/ruby-style/
Ruby
Find file
Latest commit 0bf6662 @jeremyevans Work with modern versions of RDoc
Remove doc_rforge task.
Failed to load latest commit information.
bin Initial public release
lib
.gitignore Ignore ruby-style gems
LICENSE Add ability to specify :environment key in config file for updating t…
README Add ability to specify :environment key in config file for updating t…
Rakefile Work with modern versions of RDoc
ruby-style.gemspec

README

= 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.
Something went wrong with that request. Please try again.