diff --git a/doc/buildweb.py b/doc/buildweb.py index dcfd60de..29c25186 100755 --- a/doc/buildweb.py +++ b/doc/buildweb.py @@ -8,6 +8,7 @@ from __future__ import with_statement import codecs import datetime +import inspect import os import subprocess as sp import sys @@ -52,7 +53,7 @@ class Site(object): print "" print "Updating css..." try: - sp.check_call(["compass", "compile"]) + sp.check_call(["compass", "compile", "--boring"]) except sp.CalledProcessError: print "Failed to update CSS" @@ -89,6 +90,8 @@ class Page(object): basename, oldext = os.path.splitext(filename) oldext = oldext.lower()[1:] converter = getattr(self, "convert_%s" % oldext, lambda x: x) + if "insert_settings" in self.headers: + body = body % {"settings": self.format_settings()} self.body = converter(body) newext = self.headers.get('ext', '.html') @@ -120,14 +123,108 @@ class Page(object): if not tmpl_name: return self.body - kwargs = {"conf": conf, "body": self.body, "url": self.url()} + kwargs = { + "conf": conf, + "body": self.body, + "url": self.url() + } kwargs.update(self.headers) return self.site.get_template(tmpl_name).render(kwargs) def convert_rst(self, body): - parts = publish_parts(source=body, writer_name="html") + overrides = {"initial_header_level": 2} + parts = publish_parts( + source=body, + writer_name="html", + settings_overrides=overrides + ) return parts['html_body'] + def format_settings(self): + currdir = os.path.dirname(__file__) + sys.path.insert(0, os.path.join(currdir, "..")) + import gunicorn.config as guncfg + ret = [] + for i, s in enumerate(guncfg.KNOWN_SETTINGS): + if i == 0 or s.section != guncfg.KNOWN_SETTINGS[i-1].section: + ret.append("%s\n%s\n\n" % (s.section, "+" * len(s.section))) + ret.append(self.fmt_setting2(s)) + return ''.join(ret) + + def fmt_setting2(self, s): + if callable(s.default): + val = inspect.getsource(s.default) + val = "\n".join(" %s" % l for l in val.splitlines()) + val = " ::\n\n" + val + else: + val = "``%s``" % s.default + + if s.cli and s.meta: + args = ["%s %s" % (arg, s.meta) for arg in s.cli] + cli = ', '.join(args) + elif s.cli: + cli = ", ".join(s.cli) + + out = [] + out.append("%s" % s.name) + out.append("~" * len(s.name)) + out.append("") + if s.cli: + out.append("* ``%s``" % cli) + out.append("* %s" % val) + out.append("") + out.append(s.desc) + out.append("") + out.append("") + return "\n".join(out) + + def fmt_setting(self, s): + out = [] + lines = s.desc.splitlines() + width = max(map(lambda x: len(x), lines)) + + if not callable(s.default): + val = '%s' % s.default + else: + val = '' + + if s.cli and s.meta: + args = ["%s %s" % (arg, s.meta) for arg in s.cli] + cli = ', '.join(args) + elif s.cli: + cli = ", ".join(s.cli) + else: + cli = "N/A" + + width = 80 + namelen = 20 + deflen = 20 + clilen = width - (namelen + deflen + 4) + + args = ("-" * namelen, "-" * deflen, "-" * clilen) + out.append("+%s+%s+%s+" % args) + + names = "| %s" % s.name + names += " " * (namelen - (len(s.name) + 2)) + names += " | %s" % val + names += " " * (deflen - (len(val) + 2)) + names += " | %s" % cli + names += " " * (clilen - (len(cli) + 1)) + names += "|" + out.append(names) + + out.append(out[0].replace("-", "=")) + + for l in lines: + l = l.rstrip("\n") + if len(l) < width: + l += " " * ((width - 2) - len(l)) + out.append("|%s|" % l) + out.append("+%s+" % ("-" * (width - 2))) + out.extend(["", ""]) + + return "\n".join(out) + def main(): Site().render() diff --git a/doc/css/style.sass b/doc/css/style.sass index dfc7fb8e..b051b8f1 100644 --- a/doc/css/style.sass +++ b/doc/css/style.sass @@ -1,10 +1,159 @@ +@import compass/css3 @import compass/reset +@import compass/utilities/general +@import compass/utilities/lists -$bg_color: #F9F9F9 -$font_color: #2A2A2A +$separator: #CCCCCC + +$size_body_width: 700px +$size_toc_width: 150px + +$color_a: #569633 +$color_bg: #F9F9F9 +$color_font: #2A2A2A +$color_footer_a: #444444 +$color_footer_border: #CCCCCC +$color_headings: #489848 +$color_headings_border: #CCCCCC +$color_menu_border: #BBBBBB +$color_menu_a: #489848 +$color_note_before: #489848 +$color_note_border: #489848 +$color_pre_bg: #FFFFDD +$color_th_border: #000000 body - background: $bg_color - color: $font_color + background: $color_bg + color: $color_font + line-height: 18px font-family: Arial, sans-serif + font-size: 13px + +div.container + display: block + width: $size_body_width + margin: 0 auto + +#header + margin: 1em auto + text-align: center + +#menu + width: 100% + margin: 1em 0 + border-bottom: 1px solid $color_menu_border + text-align: center + ul + +no-bullets + display: inline + li + display: inline + margin-right: 15px + text-align: center + a + font-size: 20px + font-weight: 700 + color: $color_menu_a + text-decoration: none + +#contents.sidebar + float: right + width: $size_toc_width + ul + margin-bottom: 0.2em + +p.topic-title + display: none + +div.section + margin-right: $size_toc_width + 20px + +div.section div.section + margin-right: 0 + +div.section ul + margin-left: 15px + +no-bullets + +h1, h2, h3, h4 + color: $color_headings + +h1 + margin-top: 10px + font-size: 26px + +h2 + border-bottom: 5px solid $color_headings_border + margin-bottom: 13px + padding-bottom: 3px + font-size: 20px + font-weight: 700 + +h3 + border-bottom: 1px solid $color_headings_border + margin-bottom: 13px + font-weight: 700 + +a + color: $color_a + text-decoration: none + +p + margin-bottom: 1em font-size: 1em + +ol + list-style: decimal + margin-left: 2em + margin-bottom: 13px + +ul + list-style: disc + margin-left: 2em + margin-bottom: 13px + +pre, tt + font-family: 'andale mono', 'lucida console', monospace + font-size: 12px + background: $color_pre_bg + +pre + white-space: pre + margin: 3px 3px 2em 3px + padding: 8px 20px + +.note + border-top: 1px solid $color_note_border + border-bottom: 1px solid $color_note_border + padding: .6em .6em .6em 80px + margin-bottom: 2em + position: relative + p.admonition-title:before + content: "!" + font-size: 60px + font-weight: bold + color: $color_note_before + position: absolute + top: 30px + left: 30px + font-family: helvetica,arial + p.admonition-title + font-weight: 700 + margin: 0 + margin-bottom: 4px + padding: 0 + p.last + padding: 0 + margin: 0 + +#footer + border-top: 1px solid $color_footer_border + clear: both + display: block + width: 100% + margin-top: 3em + padding-top: 1em + text-align: center + font-size: 0.8em + a + color: $color_footer_a diff --git a/doc/htdocs/configuration.html b/doc/htdocs/configuration.html index 9b28d197..bf36c537 100644 --- a/doc/htdocs/configuration.html +++ b/doc/htdocs/configuration.html @@ -4,56 +4,31 @@ Green Unicorn - The Configuration File - - - - + -
- - - - - - -
+
+ + +

The Configuration File

Gunicorn 0.5 introduced the ability to use a Python configuration file. Gunicorn will look for gunicorn.conf.py in the current working directory or what ever path is specified on the command line with the -c option.

-

Example gunicorn.conf.py

+

Example gunicorn.conf.py

 backlog = 2048              # The listen queue size for the server socket
 bind = "127.0.0.1:8000"     # Or "unix:/tmp/gunicorn.sock"
@@ -85,7 +60,7 @@ before_exec=lambda server: server.log.info("Forked child, reexecuting"
 
-

Parameter Descriptions

+

Parameter Descriptions

after_fork(server, worker):
This is called by the worker after initialization.
@@ -150,12 +125,10 @@ Eventlet or Gevent arbiter. The default is 1000.
- - - -
\ No newline at end of file diff --git a/doc/htdocs/configure.html b/doc/htdocs/configure.html new file mode 100644 index 00000000..94c36ade --- /dev/null +++ b/doc/htdocs/configure.html @@ -0,0 +1,470 @@ + + + + + Green Unicorn - Configure + + + + +
+ + +
+
+ +
+

Overview

+

Gunicorn pulls configuration information from three distinct places.

+

The first place that Gunicorn will read configuration from is the framework +specific configuration file. Currently this only affects Paster applications.

+

The second source of configuration information is a configuration file that is +optionally specified on the command line. Anything specified in the Gunicorn +config file will override any framework specific settings.

+

Lastly, the command line arguments used to invoke Gunicorn are the final place +considered for configuration settings. If an option is specified on the command +line, this is the value that will be used.

+
+
Once again, in order of least to most authoritative:
+
    +
  1. Framework Settings
  2. +
  3. Configuration File
  4. +
  5. Command Line
  6. +
+
+
+
+
+

Framework Settings

+

Currently, only Paster applications have access to framework specific +settings. If you have ideas for providing settings to WSGI applications or +pulling information from Django's settings.py feel free to open an issue to +let us know.

+
+

Paster Applications

+

In your INI file, you can specify to use Gunicorn as the server like such:

+
+[server:main]
+use = egg:gunicorn#main
+host = 192.168.0.1
+port = 80
+workers = 2
+proc_name = brim
+
+

Any parameters that Gunicorn knows about will automatically be inserted into +the base configuration. Remember that these will be overridden by the config +file and/or the command line.

+
+
+
+

Configuration File

+

The configuration file should be a valid Python source file. It only needs to +be readable from the file system. More specifically, it does not need to be +importable. Any Python is valid. Just consider that this will be run every time +you start Gunicorn (including when you signal Gunicorn to reload).

+

To set a parameter, just assign to it. There's no special syntax. The values +you provide will be used for the configuration values.

+

For instance:

+
+import os
+
+def numCPUs():
+    if not hasattr(os, "sysconf"):
+        raise RuntimeError("No sysconf detected.")
+    return os.sysconf("SC_NPROCESSORS_ONLN")
+
+bind = "127.0.0.1:8000"
+workers = numCPUs() * 2 + 1
+
+
+
+

Command Line

+

If an option is specified on the command line, it overrides all other values +that may have been specified in the app specific settings, or in the optional +configuration file. Not all Gunicorn settings are available to be set from the +command line. To see the full list of command line settings you can do the +usual:

+
+$ gunicorn -h
+
+

There is also a --version flag available to the command line scripts that +isn't mentioned in the list of settings.

+
+
+

Settings

+

This is an exhaustive list of settings for Gunicorn. Some settings are only +able to be set from a configuration file. The setting name is what should be +used in the configuration file. The command line arguments are listed as well +for reference on setting at the command line.

+
+

Config File

+
+

config

+
    +
  • -c FILE, --config FILE
  • +
  • None
  • +
+

The path to a Gunicorn config file.

+

Only has an effect when specified on the command line or as part of an +application specific configuration.

+
+
+
+

Server Socket

+
+

bind

+
    +
  • -b ADDRESS, --bind ADDRESS
  • +
  • 127.0.0.1:8000
  • +
+

The socket to bind.

+

A string of the form: 'HOST', 'HOST:PORT', 'unix:PATH'. An IP is a valid +HOST.

+
+
+

backlog

+
    +
  • --backlog INT
  • +
  • 2048
  • +
+

The maximum number of pending connections.

+

This refers to the number of clients that can be waiting to be served. +Exceeding this number results in the client getting an error when +attempting to connect. It should only affect servers under significant +load.

+

Must be a positive integer. Generally set in the 64-2048 range.

+
+
+
+

Worker Processes

+
+

workers

+
    +
  • -w INT, --workers INT
  • +
  • 1
  • +
+

The number of worker process for handling requests.

+

A positive integer generally in the 2-4 x $(NUM_CORES) range. You'll +want to vary this a bit to find the best for your particular +application's work load.

+
+
+

worker_class

+
    +
  • -k STRING, --worker-class STRING
  • +
  • egg:gunicorn#sync
  • +
+

The type of workers to use.

+

The default async class should handle most 'normal' types of work loads. +You'll want to read http://gunicorn.org/design.hml for information on +when you might want to choose one of the other worker classes.

+

An string referring to a 'gunicorn.workers' entry point or a +MODULE:CLASS pair where CLASS is a subclass of +gunicorn.workers.base.Worker.

+

The default provided values are:

+
    +
  • egg:gunicorn#sync
  • +
  • egg:gunicorn#eventlet - Requires eventlet >= 0.9.7
  • +
  • egg:gunicorn#gevent - Requires gevent >= 0.12.2 (?)
  • +
  • egg:gunicorn#tornado - Requires tornado >= 0.2
  • +
+
+
+

worker_connections

+
    +
  • --worker-connections INT
  • +
  • 1000
  • +
+

The maximum number of simultaneous clients.

+

This setting only affects the Eventlet and Gevent worker types.

+
+
+

timeout

+
    +
  • -t INT, --timeout INT
  • +
  • 30
  • +
+

Workers silent for more than this many seconds are killed and restarted.

+

Generally set to thirty seconds. Only set this noticeably higher if +you're sure of the repercussions for sync workers. For the non sync +workers it just means that the worker process is still communicating and +is not tied to the length of time required to handle a single request.

+
+
+

keepalive

+
    +
  • --keep-alive INT
  • +
  • 2
  • +
+

The number of seconds to wait for requests on a Keep-Alive connection.

+

Generally set in the 1-5 seconds range.

+
+
+
+

Debugging

+
+

debug

+
    +
  • -d, --debug
  • +
  • False
  • +
+

Turn on debugging in the server.

+

This limits the number of worker processes to 1 and changes some error +handling that's sent to clients.

+
+
+

spew

+
    +
  • --spew
  • +
  • False
  • +
+

Install a trace function that spews every line executed by the server.

+

This is the nuclear option.

+
+
+
+

Server Mechanics

+
+

daemon

+
    +
  • -D, --daemon
  • +
  • False
  • +
+

Daemonize the Gunicorn process.

+

Detaches the server from the controlling terminal and enters the +background.

+
+
+

pidfile

+
    +
  • -p FILE, --pid FILE
  • +
  • None
  • +
+

A filename to use for the PID file.

+

If not set, no PID file will be written.

+
+
+

user

+
    +
  • -u USER, --user USER
  • +
  • None
  • +
+

Switch worker processes to run as this user.

+

A valid user id (as an integer) or the name of a user that can be +retrieved with a call to pwd.getpwnam(value) or None to not change +the worker process user.

+
+
+

group

+
    +
  • -g GROUP, --group GROUP
  • +
  • None
  • +
+

Switch worker process to run as this group.

+

A valid group id (as an integer) or the name of a user that can be +retrieved with a call to pwd.getgrnam(value) or None to not change +the worker processes group.

+
+
+

umask

+
    +
  • -m INT, --umask INT
  • +
  • 0
  • +
+

A bit mask for the file mode on files written by Gunicorn.

+

Note that this affects unix socket permissions.

+

A valid value for the os.umask(mode) call or a string compatible with +int(value, 0) (0 means Python guesses the base, so values like "0", +"0xFF", "0022" are valid for decimal, hex, and octal representations)

+
+
+

tmp_upload_dir

+
    +
  • None
  • +
+

Directory to store temporary request data as they are read.

+

This may disappear in the near future.

+

This path should be writable by the process permissions set for Gunicorn +workers. If not specified, Gunicorn will choose a system generated +temporary directory.

+
+
+
+

Logging

+
+

logfile

+
    +
  • --log-file FILE
  • +
  • -
  • +
+

The log file to write to.

+

"-" means log to stdout.

+
+
+

loglevel

+
    +
  • --log-level LEVEL
  • +
  • info
  • +
+

The granularity of log output

+

Valid level names are:

+
    +
  • debug
  • +
  • info
  • +
  • warning
  • +
  • error
  • +
  • critical
  • +
+
+
+
+

Process Naming

+
+

proc_name

+
    +
  • -n STRING, --name STRING
  • +
  • gunicorn
  • +
+

A base to use with setproctitle for process naming.

+

This affects things like ps and top. If you're going to be +running more than one instance of Gunicorn you'll probably want to set a +name to tell them apart. This requires that you install the setproctitle +module.

+

It defaults to 'gunicorn'.

+
+
+

default_proc_name

+
    +
  • gunicorn
  • +
+

Internal setting that is adjusted for each type of application.

+
+
+
+

Server Hooks

+
+

pre_fork

+
    +
  • +def def_pre_fork(server, worker):
    +    pass
    +
    +
  • +
+

Called just before a worker is forked.

+

The callable needs to accept two instance variables for the Arbiter and +new Worker.

+
+
+

post_fork

+
    +
  • +def def_post_fork(server, worker):
    +    server.log.info("Worker spawned (pid: %s)" % worker.pid)
    +
    +
  • +
+

Called just after a worker has been forked.

+

The callable needs to accept two instance variables for the Arbiter and +new Worker.

+
+
+

pre_exec

+
    +
  • +def def_pre_exec(server):
    +    server.log.info("Forked child, reexecuting.")
    +
    +
  • +
+

Called just before a new master process is forked.

+

The callable needs to accept a single instance variable for the Arbiter.

+
+
+
+
+ +
+ +
+ + \ No newline at end of file diff --git a/doc/htdocs/css/style.css b/doc/htdocs/css/style.css index 7c9e8254..20d1294c 100644 --- a/doc/htdocs/css/style.css +++ b/doc/htdocs/css/style.css @@ -58,10 +58,208 @@ a img { border: none; } -/* line 6, ../../css/style.sass */ +/* line 25, ../../css/style.sass */ body { background: #f9f9f9; color: #2a2a2a; + line-height: 18px; font-family: Arial, sans-serif; + font-size: 13px; +} + +/* line 32, ../../css/style.sass */ +div.container { + display: block; + width: 700px; + margin: 0 auto; +} + +/* line 37, ../../css/style.sass */ +#header { + margin: 1em auto; + text-align: center; +} + +/* line 41, ../../css/style.sass */ +#menu { + width: 100%; + margin: 1em 0; + border-bottom: 1px solid #bbbbbb; + text-align: center; +} +/* line 46, ../../css/style.sass */ +#menu ul { + list-style: none; + display: inline; +} +/* line 11, ../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.10.1/frameworks/compass/stylesheets/compass/utilities/lists/_bullets.scss */ +#menu ul li { + list-style-image: none; + list-style-type: none; + margin-left: 0px; +} +/* line 49, ../../css/style.sass */ +#menu ul li { + display: inline; + margin-right: 15px; + text-align: center; +} +/* line 53, ../../css/style.sass */ +#menu ul li a { + font-size: 20px; + font-weight: 700; + color: #489848; + text-decoration: none; +} + +/* line 59, ../../css/style.sass */ +#contents.sidebar { + float: right; + width: 150px; +} +/* line 62, ../../css/style.sass */ +#contents.sidebar ul { + margin-bottom: 0.2em; +} + +/* line 65, ../../css/style.sass */ +p.topic-title { + display: none; +} + +/* line 68, ../../css/style.sass */ +div.section { + margin-right: 170px; +} + +/* line 71, ../../css/style.sass */ +div.section div.section { + margin-right: 0; +} + +/* line 74, ../../css/style.sass */ +div.section ul { + margin-left: 15px; + list-style: none; +} +/* line 11, ../../../../../../../../Library/Ruby/Gems/1.8/gems/compass-0.10.1/frameworks/compass/stylesheets/compass/utilities/lists/_bullets.scss */ +div.section ul li { + list-style-image: none; + list-style-type: none; + margin-left: 0px; +} + +/* line 78, ../../css/style.sass */ +h1, h2, h3, h4 { + color: #489848; +} + +/* line 81, ../../css/style.sass */ +h1 { + margin-top: 10px; + font-size: 26px; +} + +/* line 85, ../../css/style.sass */ +h2 { + border-bottom: 5px solid #cccccc; + margin-bottom: 13px; + padding-bottom: 3px; + font-size: 20px; + font-weight: 700; +} + +/* line 92, ../../css/style.sass */ +h3 { + border-bottom: 1px solid #cccccc; + margin-bottom: 13px; + font-weight: 700; +} + +/* line 97, ../../css/style.sass */ +a { + color: #569633; + text-decoration: none; +} + +/* line 101, ../../css/style.sass */ +p { + margin-bottom: 1em; font-size: 1em; } + +/* line 105, ../../css/style.sass */ +ol { + list-style: decimal; + margin-left: 2em; + margin-bottom: 13px; +} + +/* line 110, ../../css/style.sass */ +ul { + list-style: disc; + margin-left: 2em; + margin-bottom: 13px; +} + +/* line 115, ../../css/style.sass */ +pre, tt { + font-family: "andale mono", "lucida console", monospace; + font-size: 12px; + background: #ffffdd; +} + +/* line 120, ../../css/style.sass */ +pre { + white-space: pre; + margin: 3px 3px 2em 3px; + padding: 8px 20px; +} + +/* line 125, ../../css/style.sass */ +.note { + border-top: 1px solid #489848; + border-bottom: 1px solid #489848; + padding: 0.6em 0.6em 0.6em 80px; + margin-bottom: 2em; + position: relative; +} +/* line 131, ../../css/style.sass */ +.note p.admonition-title:before { + content: "!"; + font-size: 60px; + font-weight: bold; + color: #489848; + position: absolute; + top: 30px; + left: 30px; + font-family: helvetica, arial; +} +/* line 140, ../../css/style.sass */ +.note p.admonition-title { + font-weight: 700; + margin: 0; + margin-bottom: 4px; + padding: 0; +} +/* line 145, ../../css/style.sass */ +.note p.last { + padding: 0; + margin: 0; +} + +/* line 149, ../../css/style.sass */ +#footer { + border-top: 1px solid #cccccc; + clear: both; + display: block; + width: 100%; + margin-top: 3em; + padding-top: 1em; + text-align: center; + font-size: 0.8em; +} +/* line 158, ../../css/style.sass */ +#footer a { + color: #444444; +} diff --git a/doc/htdocs/deploy.html b/doc/htdocs/deploy.html new file mode 100644 index 00000000..13dad92b --- /dev/null +++ b/doc/htdocs/deploy.html @@ -0,0 +1,194 @@ + + + + + Green Unicorn - Deploy + + + + +
+ + +
+
+ +
+

Nginx Configuration

+

Although there are many HTTP proxies available, we strongly advise that you +use Nginx. If you choose another proxy server you need to make sure that it +buffers slow clients when you use default Gunicorn workers. Without this +buffering Gunicorn will be easily susceptible to denial-of-service attacks. +You can use slowloris to check if your proxy is behaving properly.

+

An example configuration file for fast clients with Nginx:

+
+worker_processes 1;
+
+user nobody nogroup;
+pid /tmp/nginx.pid;
+error_log /tmp/nginx.error.log;
+
+events {
+    worker_connections 1024;
+    accept_mutex off;
+}
+
+http {
+    include mime.types;
+    default_type application/octet-stream;
+    access_log /tmp/nginx.access.log combined;
+    sendfile on;
+
+    upstream app_server {
+        server unix:/tmp/gunicorn.sock fail_timeout=0;
+        # For a TCP configuration:
+        # server 192.168.0.7:8000 fail_timeout=0;
+    }
+
+    server {
+        listen 80 default;
+        client_max_body_size 4G;
+        server_name _;
+
+        keepalive_timeout 5;
+
+        # path for static files
+        root /path/to/app/current/public;
+
+        location / {
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_set_header Host $http_host;
+            proxy_redirect off;
+
+            if (!-f $request_filename) {
+                proxy_pass http://app_server;
+                break;
+            }
+        }
+
+        error_page 500 502 503 504 /500.html;
+        location = /500.html {
+            root /path/to/app/current/public;
+        }
+    }
+}
+
+

If you want to be able to handle streaming request/responses or other fancy +features like Comet, Long polling, or Web sockets, you need to turn off the +proxy buffering. When you do this you must run with one of the async worker +classes.

+

To turn off buffering, you only need to add proxy_buffering off; to your +location block:

+
+...
+location / {
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header Host $http_host;
+    proxy_redirect off;
+    proxy_buffering off;
+
+    if (!-f $request_filename) {
+        proxy_pass http://app_server;
+        break;
+    }
+}
+...
+
+
+
+

Using Virtualenv

+

To serve an app from a Virtualenv it is generally easiest to just install +Gunicorn directly into the Virtualenv. This will create a set of Gunicorn +scripts for that Virtualenv which can be used to run applications normally.

+

If you have Virtualenv installed, you should be able to do something like +this:

+
+$ mkdir ~/venvs/
+$ virtualenv ~/venvs/webapp
+$ source ~/venvs/webapp/bin/activate
+$ ~/venvs/webapp/bin/easy_install -U gunicorn
+$ deactivate
+
+

Then you just need to use one of the three Gunicorn scripts that was installed +into ~/venvs/webapp/bin.

+
+
+

Monitoring

+
+

Note

+

Make sure that when using either of these service monitors you do not +enable the Gunicorn's daemon mode. These monitors expect that the process +they launch will be the process they need to monior. Daemonizing +will fork-exec which creates an unmonitored process and generally just +confuses the monitor services.

+
+
+

Runit

+

A popular method for deploying Gunicorn is to have it monitored by runit. +An example service definition:

+
+#!/bin sh
+
+GUNICORN=/usr/local/bin/gunicorn
+ROOT=/path/to/project
+PID=/var/run/gunicorn.pid
+
+APP=main:application
+
+if [ -f $PID ]; then rm $PID fi
+
+cd $ROOT
+exec $GUNICORN -C $ROOT/gunicorn.conf.py --pidfile=$PID $APP
+
+
+
+

Supervisor

+

Another useful tool to monitor and control Gunicorn is Supervisor. A +simple configuration is:

+
+[program:gunicorn]
+command=/usr/local/bin/gunicorn main:application -c /path/to/project/gunicorn.conf.py
+directory=/path/to/project
+user=nobody
+autostart=true
+autorestart=true
+redirect_stderr=True
+
+
+
+
+ +
+ +
+ + \ No newline at end of file diff --git a/doc/htdocs/deployment.html b/doc/htdocs/deployment.html index 34cf3ce0..08a96df2 100644 --- a/doc/htdocs/deployment.html +++ b/doc/htdocs/deployment.html @@ -4,53 +4,28 @@ Green Unicorn - Deployment - - - - + -
- - - - - - -
+
+ + +

Production Setup

-

Synchronous vs Asynchronous workers

+

Synchronous vs Asynchronous workers

The default configuration of Gunicorn assumes that your application code is mostly CPU bound. The default worker class is a simple single threaded loop that just processes requests as they are received. In general, most applications will @@ -72,7 +47,7 @@ of free worker processes (because they're all stuck waiting for data).

-

Basic Nginx Configuration

+

Basic Nginx Configuration

Although there are many HTTP proxies available, we strongly advise that you use Nginx. If you choose another proxy server you need to make sure that it buffers slow clients when you use default Gunicorn workers. Without this @@ -154,7 +129,7 @@ location / {

-

Working with Virtualenv

+

Working with Virtualenv

To serve an app from a Virtualenv it is generally easiest to just install Gunicorn directly into the Virtualenv. This will create a set of Gunicorn scripts for that Virtualenv which can be used to run applications normally.

@@ -171,7 +146,7 @@ $ deactivate into ~/venvs/webapp/bin.

-

Daemon Monitoring

+

Daemon Monitoring

Note

Make sure that when using either of these service monitors you do not @@ -210,12 +185,10 @@ redirect_stderr=True

- - - -
\ No newline at end of file diff --git a/doc/htdocs/design.html b/doc/htdocs/design.html new file mode 100644 index 00000000..0ae1a4a3 --- /dev/null +++ b/doc/htdocs/design.html @@ -0,0 +1,128 @@ + + + + + Green Unicorn - Design + + + + +
+ + +
+
+ +
+

Server Model

+

Gunicorn is based on the pre-fork worker model. This means that there is a +central master process that manages a set of worker processes. The master +never knows anything about individual clients. All requests and responses are +handled completely by worker processes.

+
+

Master

+

The master process is a simple loop that listens for various process signals +and reacts accordingly. It manages the list of running workers by listening +for signals like TTIN, TTOU, and CHLD. TTIN and TTOU tell the master to +increase or decrease the number of running workers. CHLD indicates that a child +process has terminated, in this case the master process automatically restarts +the failed worker.

+
+
+

Sync Workers

+

The most basic and the default worker type is a synchronous worker class that +handles a single request at a time. This model is the simplest to reason about +as any errors will affect at most a single request. Though as we describe below +only processing a single request at a time requires some assumptions about how +applications are programmed.

+
+
+

Async Workers

+

The asynchronous workers available are based on Greenlets (via Eventlet and +Gevent). Greenlets are an implementation of cooperative multi-threading for +Python. In general, an application should be able to make use of these worker +classes with no changes.

+
+
+

Tornado Workers

+

There's also a Tornado worker class. It can be used to write applications using +the Tornado framework. Although the Tornado workers are capable of serving a +WSGI application, this is not a recommended configuration.

+
+
+
+

Choosing a Worker Type

+

The default synchronous workers assume that your application is resource bound +in terms of CPU and network bandwidth. Generally this means that your +application shouldn't do anything that takes an undefined amount of time. For +instance, a request to the internet meets this criteria. At some point the +external network will fail in such a way that clients will pile up on your +servers.

+

This resource bound assumption is why we require a buffering proxy in front of a +default configuration Gunicorn. If you exposed synchronous workers to the +internet, a DOS attack would be trivial by creating a load that trickles data to +the servers. For the curious, Slowloris is an example of this type of load.

+

Some examples of behavior requiring asynchronous workers:

+
+
    +
  • Applications making long blocking calls (Ie, external web services)
  • +
  • Serving requests directly to the internet
  • +
  • Streaming requests and responses
  • +
  • Long polling
  • +
  • Web sockets
  • +
  • Comet
  • +
+
+
+
+

How Many Workers?

+

Gunicorn relies on the operating system to provide all of the load balancing +when handling requests. Generally we recommend (2 x $num_cores) + 1 as the +number of workers to start off with. While not overly scientific, the formula +is based on the assumption that for a given core, one worker will be reading +or writing from the socket while the other worker is processing a request.

+

Obviously, your particular hardware and application are going to affect what +the optimal number of workers is. Our recommendation is to start with the above +guess and tune using TTIN and TTOU signals while the application is under load.

+

Always remember, there is such a thing as too many workers. After a point your +worker processes will start thrashing system resources decreasing the throughput +of the entire system.

+
+
+ +
+ +
+ + \ No newline at end of file diff --git a/doc/htdocs/faq.html b/doc/htdocs/faq.html index bc38c22e..9c207de1 100644 --- a/doc/htdocs/faq.html +++ b/doc/htdocs/faq.html @@ -4,104 +4,117 @@ Green Unicorn - FAQ - - - - + -
- - - - - - -
-

FAQ

-
-
How do I know which type of worker to use?
-
Test. Read the "Synchronous vs Asynchronous workers" section on the -deployment page. Test some more.
-
What types of workers are there?
-

These can all be used with the -k option and specifying them -as egg:gunicorn#$(NAME) where $(NAME) is chosen from this list.

-
-
How might I test a proxy configuration?
-
Check out slowloris for a script that will generate significant slow -traffic. If your application remains responsive through out that test you -should be comfortable that all is well with your configuration.
-
How do I reload my application in Gunicorn?
-

You can gracefully reload by sending HUP signal to gunicorn:

-
+
+
  • Server Stuff +
  • +
  • Worker Processes +
  • + +
    +
    +

    WSGI Bits

    +
    +

    How do I set SCRIPT_NAME?

    +

    By default SCRIPT_NAME is an empy string. The value could be set by +setting SCRIPT_NAME in the environment or as an HTTP header.

    +
    +
    +
    +

    Server Stuff

    +
    +

    How do I reload my application in Gunicorn?

    +

    You can gracefully reload by sending HUP signal to gunicorn:

    +
     $ kill -HUP masterpid
     
    - -
    How do I increase or decrease the number of running workers dynamically?
    -

    To increase the worker count by one:

    +
    +
    +

    How might I test a proxy configuration?

    +

    The Slowloris script is a great way to test that your proxy is correctly +buffering responses for the synchronous workers.

    +
    +
    +

    How can I name processes?

    +

    If you install the Python package setproctitle Gunicorn will set the process +names to something a bit more meaningful. This will affect the output you see +in tools like ps and top. This helps for distinguishing the master +process as well as between masters when running more than one app on a single +machine. See the proc_name setting for more information.

    +
    +
    +
    +

    Worker Processes

    +
    +

    How do I know which type of worker to use?

    +

    Read the design page for help on the various worker types.

    +
    +
    +

    What types of workers are there?

    +

    Check out the configuration docs for worker_class

    +
    + +
    +

    How can I change the number of workers dynamically?

    +
    +

    To increase the worker count by one:

     $ kill -TTIN $masterpid
     

    To decrease the worker count by one:

    -
    +
     $ kill -TTOU $masterpid
     
    - -
    How can I figure out the best number of worker processes?
    -
    Start gunicorn with an approximate number of worker processes. Then use the -TTIN and/or TTOU signals to adjust the number of workers under load.
    -
    How do I set SCRIPT_NAME?
    -
    By default SCRIPT_NAME is an empy string. The value could be set by -setting SCRIPT_NAME in the environment or as an HTTP header.
    -
    How can I name processes?
    -
    You need to install the Python package setproctitle. Then you can specify -a base process name on the command line (-n) or in the configuration -file.
    - +
    +
    +
    - - - +
    -
    \ No newline at end of file diff --git a/doc/htdocs/index.html b/doc/htdocs/index.html index 5e181a49..bb93598b 100644 --- a/doc/htdocs/index.html +++ b/doc/htdocs/index.html @@ -4,57 +4,40 @@ Green Unicorn - Welcome - - - - + -
    - - - - -
    -

    Green Unicorn

    +
    + + +
    +
    +
    +

    Green Unicorn

    Gunicorn 'Green Unicorn' is a WSGI HTTP Server for UNIX. It's a pre-fork worker model ported from Ruby's Unicorn project. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resource usage, and fairly speedy.

    Feel free to join us in #gunicorn on freenode.

    Gunicorn is released under the MIT License. See the LICENSE for more details.

    +
    -

    Features

    +

    Features

    • Designed for Unix.
    • Compatible with Python 2.x (>= 2.5)
    • @@ -72,7 +55,7 @@ or stream-based protocols over HTTP
    -

    Applications

    +

    Applications

    - +
    -
    \ No newline at end of file diff --git a/doc/htdocs/install.html b/doc/htdocs/install.html new file mode 100644 index 00000000..968d331f --- /dev/null +++ b/doc/htdocs/install.html @@ -0,0 +1,149 @@ + + + + + Green Unicorn - Install + + + + +
    + + +
    +
    + +
    +

    Requirements

    +
      +
    • Python 2.x >= 2.5 (Python 3.x will be supported soon)
    • +
    • setuptools >= 0.6c6
    • +
    • nosetests (for the test suite only)
    • +
    +
    +
    +

    With easy_install

    +

    If you don't already have easy_install available you'll want to download +and run the ez_setup.py script:

    +
    +$ curl -O http://peak.telecommunity.com/dist/ez_setup.py
    +$ sudo python ez_setup.py -U setuptools
    +
    +

    To install or upgrade to the latest released version of Gunicorn:

    +
    +$ sudo easy_install -U gunicorn
    +
    +
    +
    +

    From Source

    +

    You can install Gunicorn from source just as you would install any other +Python package. Gunicorn uses setuptools which will automatically fetch all +dependencies (including setuptools itself).

    +

    You can download a tarball of the latest sources from GitHub Downloads or +fetch them with git:

    +
    +# Using git:
    +$ git clone git://github.com/benoitc/gunicorn.git
    +$ cd gunicorn
    +
    +# Or using a tarball:
    +$ wget http://github.com/benoitc/gunicorn/tarball/master -o gunicorn.tar.gz
    +$ tar -xvzf gunicorn.tar.gz
    +$ cd gunicorn-$HASH/
    +
    +# Install
    +$ sudo python setup.py install
    +
    +

    If you've cloned the git repository, its highly recommended that you use the +develop command which will allow you to use Gunicorn from the source +directory. This will allow you to keep up to date with development on GitHub as +well as make changes to the source:

    +
    +$ python setup.py develop
    +
    +
    +
    +

    Async Workers

    +

    You may also want to install Eventlet or Gevent if you expect that your +application code may need to pause for extended periods of time during request +processing. Check out the design docs for more information on when you'll +want to consider one of the alternate worker types.

    +
    +$ easy_install -U greenlet  # Required for both
    +$ easy_install -U eventlet  # For eventlet workers
    +$ easy_install -U gevent    # For gevent workers
    +
    +
    +

    Note

    +

    If installing greenlet fails you probably need to install +the Python headers. These headers are available in most package +managers. On Ubuntu the package name for apt-get is +python-dev.

    +

    Gevent also requires that libevent 1.4.x or 2.0.4 is installed. +This could be a more recent version than what is available in your +package manager. If Gevent fails to build even with libevent +installed, this is the most likely reason.

    +
    +
    +
    +

    Ubuntu/Debian

    +

    If you use Ubuntu karmic, you can update your system with packages from +our PPA by adding ppa:bchesneau/gunicorn to your system's Software +Sources.

    +

    Or this PPA can be added to your system manually by copying the lines below +and adding them to your system's software sources:

    +
    +deb http://ppa.launchpad.net/bchesneau/gunicorn/ubuntu karmic main
    +deb-src http://ppa.launchpad.net/bchesneau/gunicorn/ubuntu karmic main
    +
    +
    +

    Signing key

    +
    +1024R/15E5EB06
    +
    +
    +
    +

    Fingerprint

    +
    +49AEEDFF5CDCD82CEA8AB4DABC981A8115E5EB06
    +
    +
    +
    +
    + +
    + +
    + + \ No newline at end of file diff --git a/doc/htdocs/installation.html b/doc/htdocs/installation.html index 9cc3033c..2d7d4ac6 100644 --- a/doc/htdocs/installation.html +++ b/doc/htdocs/installation.html @@ -4,53 +4,28 @@ Green Unicorn - Installing Gunicorn - - - - + -
    - - - - - - -
    +
    + + +

    Installation

    -

    Requirements

    +

    Requirements

    • Python 2.x >= 2.5 (Python 3.x will be supported soon)
    • setuptools >= 0.6c6
    • @@ -71,12 +46,12 @@ $ sudo easy_install -U gunicorn
    -

    Installing from source

    +

    Installing from source

    You can install Gunicorn from source just as you would install any other Python package. Gunicorn uses setuptools which will automatically fetch all dependencies (including setuptools itself).

    -

    Get a Copy

    +

    Get a Copy

    You can download a tarball of the latest sources from GitHub Downloads or fetch them with git:

    @@ -84,7 +59,7 @@ $ git clone git://github.com/benoitc/gunicorn.git
     
    -

    Installation

    +

    Installation

     $ python setup.py install
     
    @@ -98,7 +73,7 @@ $ python setup.py develop
    -

    Enabling async workers

    +

    Enabling async workers

    You may also want to install Eventlet or Gevent if you expect that your application code may need to pause for extended periods of time during request processing. Check out the FAQ for more information on when you'll @@ -122,7 +97,7 @@ installed, this is the most likely reason.

    -

    Installing on Ubuntu/Debian systems

    +

    Installing on Ubuntu/Debian systems

    If you use Ubuntu karmic, you can update your system with packages from our PPA by adding ppa:bchesneau/gunicorn to your system's Software Sources.

    @@ -143,12 +118,10 @@ deb-src http://ppa.launchpad.net/bchesneau/gunicorn/ubuntu karmic main
    - - - -
    - \ No newline at end of file + diff --git a/doc/htdocs/news.html b/doc/htdocs/news.html index d91547ba..dc69fa2c 100644 --- a/doc/htdocs/news.html +++ b/doc/htdocs/news.html @@ -4,53 +4,31 @@ Green Unicorn - News - - - - + -
    - - - - - - -
    -

    News

    +
    + + +
    +
    -

    0.9.0-dev / 2010-05-17

    +

    0.9.0-dev / 2010-05-17

    • Fix pidfile
    • Fix QUIT/HUP in async workers
    • @@ -89,8 +67,8 @@ are forked.
    • Delay application loading until after processing all configuration
    -
    -

    0.8.0 / 2010-04-22

    +
    +

    0.8.0 / 2010-04-22

    • Refactored Worker management for better async support. Now use the -k option to set the type of request processing to use
    • @@ -105,8 +83,8 @@ to set the type of request processing to use
    • Fix a bug in start_response on error
    -
    -

    0.7.1 / 2010-04-01

    +
    +

    0.7.1 / 2010-04-01

    • Fix bug when responses have no body.
    @@ -128,22 +106,22 @@ to set the type of request processing to use
  • Fix Exception Error
  • -
    -

    0.6.4 / 2010-03-08

    +
    +

    0.6.4 / 2010-03-08

    • Use cStringIO for performance when possible.
    • Fix worker freeze when a remote connection closes unexpectedly.
    -
    -

    0.6.3 / 2010-03-07

    +
    +

    0.6.3 / 2010-03-07

    • Make HTTP parsing faster.
    • Various bug fixes
    -
    -

    0.6.2 / 2010-03-01

    +
    +

    0.6.2 / 2010-03-01

    • Added support for chunked response.
    • Added proc_name option to the config file.
    • @@ -153,31 +131,31 @@ temporary data.
    • Workers are now murdered by age (the oldest is killed first).
    -
    -

    0.6.1 / 2010-02-24

    +
    +

    0.6.1 / 2010-02-24

    • Added gunicorn config file support for Django admin command
    • Fix gunicorn config file. -c was broken.
    • Removed TTIN/TTOU from workers which blocked other signals.
    -
    -

    0.6 / 2010-02-22

    +
    +

    0.6 / 2010-02-22

    • Added setproctitle support
    • Change privilege switch behavior. We now work like NGINX, master keeps the permissions, new uid/gid permissions are only set for workers.
    -
    -

    0.5.1 / 2010-02-22

    +
    +

    0.5.1 / 2010-02-22

    • Fix umask
    • Added Debian packaging
    -
    -

    0.5 / 2010-02-20

    +
    +

    0.5 / 2010-02-20

    • Added configuration file handler.
    • Added support for pre/post fork hooks
    • @@ -194,12 +172,11 @@ permissions, new uid/gid permissions are only set for workers.
    - - - +
    -
    - \ No newline at end of file + diff --git a/doc/htdocs/run.html b/doc/htdocs/run.html new file mode 100644 index 00000000..f5046b8d --- /dev/null +++ b/doc/htdocs/run.html @@ -0,0 +1,165 @@ + + + + + Green Unicorn - Run + + + + +
    + + +
    +
    + +
    +

    Commands

    +

    After installing Gunicorn you will have access to three command line scripts +that can be used for serving the various supported web frameworks:

    +
    +
      +
    • gunicorn
    • +
    • gunicorn_django
    • +
    • gunicorn_paster
    • +
    +
    +
    +

    gunicorn

    +

    The first and most basic script is used to serve 'bare' WSGI applications +that don't require a translation layer. Basic usage:

    +
    +$ gunicorn [OPTIONS] APP_MODULE
    +
    +

    Where APP_MODULE is of the pattern $(MODULE_NAME):$(VARIABLE_NAME). The +module name can be a full dotted path. The variable name refers to a WSGI +callable that should be found in the specified module.

    +

    Example with test app:

    +
    +$ cd examples
    +$ cat test.py
    +# -*- coding: utf-8 -
    +#
    +# This file is part of gunicorn released under the MIT license.
    +# See the NOTICE for more information.
    +
    +def app(environ, start_response):
    +    """Simplest possible application object"""
    +    data = 'Hello, World!\n'
    +    status = '200 OK'
    +    response_headers = [
    +        ('Content-type','text/plain'),
    +        ('Content-Length', str(len(data)))
    +    ]
    +    start_response(status, response_headers)
    +    return iter([data])
    +
    +$ gunicorn --workers=2 test:app
    +
    +
    +
    +

    gunicorn_django

    +

    You might not have guessed it, but this script is used to serve Django +applications. Basic usage:

    +
    +$ gunicorn_django [OPTIONS] [SETTINGS_PATH]
    +
    +

    By default SETTINGS_PATH will look for settings.py in the current +directory.

    +

    Example with your Django project:

    +
    +$ cd path/to/yourdjangoproject
    +$ gunicorn_django --workers=2
    +
    +
    +
    +

    gunicorn_paster

    +

    Yeah, for Paster-compatible frameworks (Pylons, TurboGears 2, ...). We +apologize for the lack of script name creativity. And some usage:

    +
    +$ gunicorn_paster [OPTIONS] paste_config.ini
    +
    +

    Simple example:

    +
    +$ cd yourpasteproject
    +$ gunicorn_paste --workers=2 development.ini
    +
    +
    +
    +
    +

    Integration

    +

    Alternatively, we also provide integration for both Django and Paster +applications in case your deployment strategy would be better served by such +invocation styles.

    +
    +

    Django ./manage.py

    +

    You can add a run_gunicorn command to your ./manage.py simply by adding +gunicorn to your INSTALLED_APPS:

    +
    +INSTALLED_APPS = (
    +    ...
    +    "gunicorn",
    +)
    +
    +

    Then you can run:

    +
    +python manage.py run_gunicorn
    +
    +
    +
    +

    paster serve

    +

    If you're wanting to keep on keeping on with the usual paster serve command, +you can specify the Gunicorn server settings in your configuration file:

    +
    +[server:main]
    +use = egg:gunicorn#main
    +host = 127.0.0.1
    +port = 5000
    +
    +

    And then as per usual:

    +
    +$ cd yourpasteproject
    +$ paster serve development.ini workers=2
    +
    +
    +
    +
    + +
    + +
    + + \ No newline at end of file diff --git a/doc/htdocs/tuning.html b/doc/htdocs/tuning.html index 83dbf3e5..a783eae0 100644 --- a/doc/htdocs/tuning.html +++ b/doc/htdocs/tuning.html @@ -4,53 +4,32 @@ Green Unicorn - Tuning - - - - + -
    - - - - - - -
    +
    + + +
    +

    Tuning

    -

    Unicorn Configuration

    +

    Unicorn Configuration

    DO NOT scale the number of workers to the number of clients you expect to have. Gunicorn should only need 4-12 worker processes to handle hundreds or thousands of simultaneous clients. Remember, Gunicorn is NOT designed for serving slow @@ -58,7 +37,7 @@ clients, that's the job of Configuration for a more thorough description of the available parameters.

    -

    Kernel Parameters

    +

    Kernel Parameters

    When dealing with large numbers of concurrent connections there are a handful of kernel parameters that you might need to adjust. Generally these should only affect sites with a very large concurrent load. These parameters are not @@ -68,7 +47,7 @@ running.

    slightly different flags. Always reference the appropriate man pages if uncertain.

    -

    File Descriptor Limits

    +

    File Descriptor Limits

    One of the first settings that usually needs to be bumped is the maximum number of open file descriptors for a given process. For the confused out there, remember that Unices treat sockets as files.

    @@ -77,7 +56,7 @@ $ sudo ulimit -n 2048
    -

    Listen Queue Size

    +

    Listen Queue Size

    Listening sockets have an associated queue of incoming connections that are waiting to be accepted. If you happen to have a stampede of clients that fill up this queue new connections will eventually start getting dropped.

    @@ -86,7 +65,7 @@ $ sudo sysctl -w kern.ipc.somaxconn="2048"
    -

    Ephemeral Port Range

    +

    Ephemeral Port Range

    After a socket is closed it enters the TIME_WAIT state. This can become an issue after a prolonged burst of client activity. Eventually the ephemeral port range is exhausted which can cause new connections to stall while they wait for a @@ -100,12 +79,11 @@ $ sudo sysctl -w net.inet.ip.portrange.first="8048"

    - - - +
    -
    \ No newline at end of file diff --git a/doc/htdocs/usage.html b/doc/htdocs/usage.html index d3e3e9ad..56e2f546 100644 --- a/doc/htdocs/usage.html +++ b/doc/htdocs/usage.html @@ -4,74 +4,52 @@ Green Unicorn - Command Line Usage - - - - + -
    - - - - - - -
    +
    + + +

    Usage

    After installing Gunicorn you will have access to three command line scripts that can be used for serving the various supported web frameworks: gunicorn, gunicorn_django, and gunicorn_paster.

    -

    Commonly Used Arguments

    +

    Commonly Used Arguments

    -
      -
    • -c CONFIG, --config=CONFIG - Specify the path to a config file
    • -
    • -b BIND, --bind=BIND - Specify a server socket to bind. Server sockets -can be any of $(HOST), $(HOST):$(PORT), or unix:$(PATH). -An IP is a valid $(HOST).
    • -
    • -w WORKERS, --workers=WORKERS - The number of worker processes. This -number should generally be between 2-4 workers per core in the server. -Check the FAQ for ideas on tuning this parameter.
    • -
    • -k WORKERCLASS, --worker-class=WORKERCLASS - The type of worker process -to run. You'll definitely want to read the production page for the -implications of this parameter. You can set this to egg:gunicorn#$(NAME) -where $(NAME) is one of sync, eventlet, gevent, or -tornado. sync is the default.
    • -
    • -n APP_NAME, --name=APP_NAME - If setproctitle is installed you can -adjust the name of Gunicorn process as they appear in the process system -table (which affects tools like ps and top).
    • -
    +
    +
    -c CONFIG, --config=CONFIG
    +
    Specify the path to a config file
    +
    -b BIND, --bind=BIND
    +
    Specify a server socket to bind. Server sockets can be any of $(HOST), +$(HOST):$(PORT), or unix:$(PATH). An IP is a valid $(HOST).
    +
    -w WORKERS, --workers=WORKERS
    +
    The number of worker processes. This number should generally be between 2-4 +workers per core in the server. Check the FAQ for ideas on tuning this +parameter.
    +
    -k WORKERCLASS, --worker-class=WORKERCLASS
    +
    The type of worker process to run. You'll definitely want to read the +production page for the implications of this parameter. You can set this +to egg:gunicorn#$(NAME) where $(NAME) is one of sync, +eventlet, gevent, or tornado. sync is the default.
    +
    -n APP_NAME, --name=APP_NAME
    +
    If setproctitle is installed you can adjust the name of Gunicorn process as +they appear in the process system table (which affects tools like ps and +top).
    +

    There are various other parameters that affect user privileges, logging, etc. You can see the complete list at the bottom of this page or as expected with:

    @@ -80,7 +58,7 @@ $ gunicorn -h
    -

    gunicorn

    +

    gunicorn

    The first and most basic script is used to server 'bare' WSGI applications that don't require a translation layer. Basic usage:

    @@ -96,7 +74,7 @@ $ gunicorn --workers=2 test:app
     
    -

    gunicorn_django

    +

    gunicorn_django

    You might not have guessed it, but this script is used to server Django applications. Basic usage:

    @@ -125,7 +103,7 @@ python manage.py run_gunicorn
     
    -

    gunicorn_paster

    +

    gunicorn_paster

    Yeah, for Paster-compatible frameworks (Pylons, TurboGears 2, ...). We apologize for the lack of script name creativity. And some usage:

    @@ -151,7 +129,7 @@ $ paster serve development.ini workers=2
     
    -

    Full Command Line Usage

    +

    Full Command Line Usage

     $ gunicorn -h
     Usage: gunicorn [OPTIONS] APP_MODULE
    @@ -185,12 +163,12 @@ Options:
     
    -

    Framework Examples

    +

    Framework Examples

    This is an incomplete list of examples of using Gunicorn with various Python web frameworks. If you have an example to add you're very much invited to submit a ticket to the issue tracker to have it included.

    -

    Itty

    +

    Itty

    Itty comes with builtin Gunicorn support. The Itty "Hello, world!" looks like such:

    @@ -204,7 +182,7 @@ run_itty(server='gunicorn')
     
    -

    Flask

    +

    Flask

    Flask applications are WSGI compatible. Given this Flask app in an importable Python module "helloflask.py":

    @@ -225,12 +203,10 @@ can be as simple as "exists in the current directory".

    - - - -
    \ No newline at end of file diff --git a/doc/site/configuration.rst b/doc/site/configuration.rst deleted file mode 100644 index 06dcb784..00000000 --- a/doc/site/configuration.rst +++ /dev/null @@ -1,132 +0,0 @@ -template: doc.html -title: The Configuration File - -The Configuration File -====================== - -Gunicorn 0.5 introduced the ability to use a Python configuration file. Gunicorn -will look for ``gunicorn.conf.py`` in the current working directory or what ever -path is specified on the command line with the ``-c`` option. - -Example gunicorn.conf.py ------------------------- - -:: - - backlog = 2048 # The listen queue size for the server socket - bind = "127.0.0.1:8000" # Or "unix:/tmp/gunicorn.sock" - daemon = False # Whether work in the background - debug = False # Some extra logging - keepalive = 2 # Time we wait for next connection (in seconds) - logfile = "-" # Name of the log file - loglevel = "info" # The level at which to log - pidfile = None # Path to a PID file - workers = 1 # Number of workers to initialize - umask = 0 # Umask to set when daemonizing - user = None # Change process owner to user - group = None # Change process group to group - proc_name = None # Change the process name - spew=False # Display trace - timeout=30 # Worker timeout - tmp_upload_dir = None # Set path used to store temporary uploads - worker_class = "egg:gunicorn#sync" # The type of request processing to use - worker_connections=1000 # Maximum number of simultaneous connections - - after_fork=lambda server, worker: server.log.info( - "Worker spawned (pid: %s)" % worker.pid) - - before_fork=lambda server, worker: True - - before_exec=lambda server: server.log.info("Forked child, reexecuting") - - when_ready=lambda server: server.log.info("Gunicorn started.") - -Parameter Descriptions ----------------------- - -after_fork(server, worker): - This is called by the worker after initialization. - -worker_class: - Define the type of worker to use. A worker process all the requests send by - the arbiter.By default the worker_class is `egg:gunicorn#sync`. This worker - only supports fast request handling requiring a buffering HTTP proxy. - - If your application requires the ability to handle prolonged requests to - provide long polling, comet, or calling an external web service you'll - need to use an async worker. Gunicorn has three async workers built in - using `Tornado`_, `Eventlet`_ or `Gevent`_. You can also use the Evenlet - worker with the `Twisted`_ helper. - -backlog: - The backlog parameter defines the maximum length for the queue of pending - connections. The default is 2048. See listen(2) for more information - -before_fork(server, worker): - This is called by the worker just before forking. - -before_exec(server): - This function is called before relaunching the master. This happens when - the master receives a HUP or USR2 signal. - -bind: - The address on which workers are listening. It can be a TCP address with a - format of ``IP:PORT`` or a Unix socket address like - ``unix:/path/to/socketfile``. - -daemon: - Whether or not to detach the server from the controlling terminal. - -debug: - If ``True``, only one worker will be launch and the variable - ``wsgi.multiprocess`` will be set to False. - -group: - The group in which worker processes will be launched. - -keepalive: - KeepAlive timeout. The default is 2 seconds, which should be enough under - most conditions for browsers to render the page and start retrieving extra - elements for. Increasing this beyond 5 seconds is not recommended. Zero - disables KeepAlive entirely. - -logfile: - The path to the log file ``-`` (stdout) by default. - -loglevel: - The level at which to log. ``info``, ``debug``, or ``error`` for instance. - Only log messages of equal or greater severity are logged. - -pidfile: - A file to store the master's PID. - -proc_name: - A name for the master process. Only takes effect if setproctitle_ is - installed. This alters the process names listed by commands like ``ps``. - -umask: - Used to set the umask when daemonizing. - -user: - The user as which worker processes will by launched. - -when_ready(server): - This is called by the arbiter just after Gunicorn started. - -worker_connections: - Number of simultaneous connections a worker can handle when used with - Eventlet or Gevent arbiter. The default is 1000. - -timeout: - Set worker timeout. - -tmp_upload_dir: - Set the path used to store temporarily the body of the request. - -.. _helper: http://bitbucket.org/which_linden/eventlet/src/tip/README.twisted -.. _Eventlet: http://eventlet.net -.. _Gevent: http://gevent.org -.. _Twisted: http://twistedmatrix.com -.. _Tornado: http://www.tornadoweb.org/ -.. _setproctitle: http://pypi.python.org/pypi/setproctitle - diff --git a/doc/site/configure.rst b/doc/site/configure.rst new file mode 100644 index 00000000..9eccd786 --- /dev/null +++ b/doc/site/configure.rst @@ -0,0 +1,101 @@ +template: doc.html +title: Configure +insert_settings: true + +.. contents:: + :class: sidebar + :backlinks: top + +Overview +-------- + +Gunicorn pulls configuration information from three distinct places. + +The first place that Gunicorn will read configuration from is the framework +specific configuration file. Currently this only affects Paster applications. + +The second source of configuration information is a configuration file that is +optionally specified on the command line. Anything specified in the Gunicorn +config file will override any framework specific settings. + +Lastly, the command line arguments used to invoke Gunicorn are the final place +considered for configuration settings. If an option is specified on the command +line, this is the value that will be used. + +Once again, in order of least to most authoritative: + 1. Framework Settings + 2. Configuration File + 3. Command Line + +Framework Settings +------------------ + +Currently, only Paster applications have access to framework specific +settings. If you have ideas for providing settings to WSGI applications or +pulling information from Django's settings.py feel free to open an issue_ to +let us know. + +.. _issue: http://github.com/benoitc/gunicorn/issues + +Paster Applications ++++++++++++++++++++ + +In your INI file, you can specify to use Gunicorn as the server like such:: + + [server:main] + use = egg:gunicorn#main + host = 192.168.0.1 + port = 80 + workers = 2 + proc_name = brim + +Any parameters that Gunicorn knows about will automatically be inserted into +the base configuration. Remember that these will be overridden by the config +file and/or the command line. + +Configuration File +------------------ + +The configuration file should be a valid Python source file. It only needs to +be readable from the file system. More specifically, it does not need to be +importable. Any Python is valid. Just consider that this will be run every time +you start Gunicorn (including when you signal Gunicorn to reload). + +To set a parameter, just assign to it. There's no special syntax. The values +you provide will be used for the configuration values. + +For instance:: + + import os + + def numCPUs(): + if not hasattr(os, "sysconf"): + raise RuntimeError("No sysconf detected.") + return os.sysconf("SC_NPROCESSORS_ONLN") + + bind = "127.0.0.1:8000" + workers = numCPUs() * 2 + 1 + +Command Line +------------ + +If an option is specified on the command line, it overrides all other values +that may have been specified in the app specific settings, or in the optional +configuration file. Not all Gunicorn settings are available to be set from the +command line. To see the full list of command line settings you can do the +usual:: + + $ gunicorn -h + +There is also a ``--version`` flag available to the command line scripts that +isn't mentioned in the list of settings. + +Settings +-------- + +This is an exhaustive list of settings for Gunicorn. Some settings are only +able to be set from a configuration file. The setting name is what should be +used in the configuration file. The command line arguments are listed as well +for reference on setting at the command line. + +%(settings)s diff --git a/doc/site/deployment.rst b/doc/site/deploy.rst similarity index 79% rename from doc/site/deployment.rst rename to doc/site/deploy.rst index 7a690456..888b25e7 100644 --- a/doc/site/deployment.rst +++ b/doc/site/deploy.rst @@ -1,38 +1,17 @@ template: doc.html -title: Deployment +title: Deploy -Production Setup -================ +.. contents:: + :class: sidebar + :backlinks: top -Synchronous vs Asynchronous workers ------------------------------------ - -The default configuration of Gunicorn assumes that your application code is -mostly CPU bound. The default worker class is a simple single threaded loop that -just processes requests as they are received. In general, most applications will -do just fine with this sort of configuration. - -This CPU bound assumption is why the default configuration needs to use a -buffering HTTP proxy like Nginx_ to protect the Gunicorn server. If we allowed -direct connections a client could send a request slowly thus starving the server -of free worker processes (because they're all stuck waiting for data). - -Example use-cases for asynchronous workers: - - * Applications making long blocking calls (Ie, to external web services) - * Serving requests directly to the internet - * Streaming requests and responses - * Long polling - * Web sockets - * Comet - -Basic Nginx Configuration -------------------------- +Nginx Configuration +------------------- Although there are many HTTP proxies available, we strongly advise that you use Nginx_. If you choose another proxy server you need to make sure that it buffers slow clients when you use default Gunicorn workers. Without this -buffering Gunicorn will be easily susceptible to Denial-Of-Service attacks. +buffering Gunicorn will be easily susceptible to denial-of-service attacks. You can use slowloris_ to check if your proxy is behaving properly. An `example configuration`_ file for fast clients with Nginx_:: @@ -110,8 +89,8 @@ To turn off buffering, you only need to add ``proxy_buffering off;`` to your } ... -Working with Virtualenv ------------------------ +Using Virtualenv +---------------- To serve an app from a Virtualenv_ it is generally easiest to just install Gunicorn directly into the Virtualenv. This will create a set of Gunicorn @@ -129,8 +108,8 @@ this:: Then you just need to use one of the three Gunicorn scripts that was installed into ``~/venvs/webapp/bin``. -Daemon Monitoring ------------------ +Monitoring +---------- .. note:: Make sure that when using either of these service monitors you do not @@ -140,6 +119,9 @@ Daemon Monitoring confuses the monitor services. +Runit ++++++ + A popular method for deploying Gunicorn is to have it monitored by runit_. An `example service`_ definition:: @@ -156,6 +138,9 @@ An `example service`_ definition:: cd $ROOT exec $GUNICORN -C $ROOT/gunicorn.conf.py --pidfile=$PID $APP +Supervisor +++++++++++ + Another useful tool to monitor and control Gunicorn is Supervisor_. A `simple configuration`_ is:: diff --git a/doc/site/design.rst b/doc/site/design.rst new file mode 100644 index 00000000..8d93cd18 --- /dev/null +++ b/doc/site/design.rst @@ -0,0 +1,94 @@ +template: doc.html +title: Design + +.. contents:: + :class: sidebar + :backlinks: top + +Server Model +============ + +Gunicorn is based on the pre-fork worker model. This means that there is a +central master process that manages a set of worker processes. The master +never knows anything about individual clients. All requests and responses are +handled completely by worker processes. + +Master +------ + +The master process is a simple loop that listens for various process signals +and reacts accordingly. It manages the list of running workers by listening +for signals like TTIN, TTOU, and CHLD. TTIN and TTOU tell the master to +increase or decrease the number of running workers. CHLD indicates that a child +process has terminated, in this case the master process automatically restarts +the failed worker. + +Sync Workers +------------ + +The most basic and the default worker type is a synchronous worker class that +handles a single request at a time. This model is the simplest to reason about +as any errors will affect at most a single request. Though as we describe below +only processing a single request at a time requires some assumptions about how +applications are programmed. + +Async Workers +------------- + +The asynchronous workers available are based on Greenlets_ (via Eventlet_ and +Gevent_). Greenlets are an implementation of cooperative multi-threading for +Python. In general, an application should be able to make use of these worker +classes with no changes. + +Tornado Workers +--------------- + +There's also a Tornado worker class. It can be used to write applications using +the Tornado framework. Although the Tornado workers are capable of serving a +WSGI application, this is not a recommended configuration. + +Choosing a Worker Type +====================== + +The default synchronous workers assume that your application is resource bound +in terms of CPU and network bandwidth. Generally this means that your +application shouldn't do anything that takes an undefined amount of time. For +instance, a request to the internet meets this criteria. At some point the +external network will fail in such a way that clients will pile up on your +servers. + +This resource bound assumption is why we require a buffering proxy in front of a +default configuration Gunicorn. If you exposed synchronous workers to the +internet, a DOS attack would be trivial by creating a load that trickles data to +the servers. For the curious, Slowloris_ is an example of this type of load. + +Some examples of behavior requiring asynchronous workers: + + * Applications making long blocking calls (Ie, external web services) + * Serving requests directly to the internet + * Streaming requests and responses + * Long polling + * Web sockets + * Comet + +How Many Workers? +================= + +Gunicorn relies on the operating system to provide all of the load balancing +when handling requests. Generally we recommend ``(2 x $num_cores) + 1`` as the +number of workers to start off with. While not overly scientific, the formula +is based on the assumption that for a given core, one worker will be reading +or writing from the socket while the other worker is processing a request. + +Obviously, your particular hardware and application are going to affect what +the optimal number of workers is. Our recommendation is to start with the above +guess and tune using TTIN and TTOU signals while the application is under load. + +Always remember, there is such a thing as too many workers. After a point your +worker processes will start thrashing system resources decreasing the throughput +of the entire system. + +.. _Greenlets: http://bitbucket.org/ambroff/greenlet +.. _Eventlet: http://eventlet.net +.. _Gevent: http://gevent.org +.. _Slowloris: http://ha.ckers.org/slowloris/ diff --git a/doc/site/faq.rst b/doc/site/faq.rst index 2e82754d..b2c9ad70 100644 --- a/doc/site/faq.rst +++ b/doc/site/faq.rst @@ -1,33 +1,71 @@ template: doc.html title: FAQ -FAQ -=== +.. contents:: Questions + :backlinks: top -How do I know which type of worker to use? - Test. Read the "Synchronous vs Asynchronous workers" section on the - deployment_ page. Test some more. -What types of workers are there? - These can all be used with the ``-k`` option and specifying them - as ``egg:gunicorn#$(NAME)`` where ``$(NAME)`` is chosen from this list. - - * ``sync`` - The default synchronous worker - * ``eventlet`` - Asynchronous workers based on Greenlets - * ``gevent`` - Asynchronous workers based on Greenlets - * ``tornado`` - Asynchronous workers based on FriendFeed's Tornado server. +WSGI Bits +========= -How might I test a proxy configuration? - Check out slowloris_ for a script that will generate significant slow - traffic. If your application remains responsive through out that test you - should be comfortable that all is well with your configuration. +How do I set SCRIPT_NAME? +------------------------- + +By default ``SCRIPT_NAME`` is an empy string. The value could be set by +setting ``SCRIPT_NAME`` in the environment or as an HTTP header. + + +Server Stuff +============ How do I reload my application in Gunicorn? - You can gracefully reload by sending HUP signal to gunicorn:: +------------------------------------------- + +You can gracefully reload by sending HUP signal to gunicorn:: $ kill -HUP masterpid -How do I increase or decrease the number of running workers dynamically? +How might I test a proxy configuration? +--------------------------------------- + +The Slowloris_ script is a great way to test that your proxy is correctly +buffering responses for the synchronous workers. + +How can I name processes? +------------------------- + +If you install the Python package setproctitle_ Gunicorn will set the process +names to something a bit more meaningful. This will affect the output you see +in tools like ``ps`` and ``top``. This helps for distinguishing the master +process as well as between masters when running more than one app on a single +machine. See the proc_name_ setting for more information. + +.. _slowloris: http://ha.ckers.org/slowloris/ +.. _setproctitle: http://pypi.python.org/pypi/setproctitle +.. _proc_name: /configure.html#proc-name + + +Worker Processes +================ + +How do I know which type of worker to use? +------------------------------------------ + +Read the design_ page for help on the various worker types. + +What types of workers are there? +-------------------------------- + +Check out the configuration docs for worker_class_ + +How can I figure out the best number of worker processes? +--------------------------------------------------------- + +Here is our recommendation for tuning the `number of workers`_. + +How can I change the number of workers dynamically? +--------------------------------------------------- + To increase the worker count by one:: $ kill -TTIN $masterpid @@ -36,21 +74,7 @@ How do I increase or decrease the number of running workers dynamically? $ kill -TTOU $masterpid -How can I figure out the best number of worker processes? - Start gunicorn with an approximate number of worker processes. Then use the - TTIN and/or TTOU signals to adjust the number of workers under load. +.. _design: /design.html +.. _worker_class: /configure.html#worker-class +.. _`number of workers`: /design.html#how-many-workers -How do I set SCRIPT_NAME? - By default ``SCRIPT_NAME`` is an empy string. The value could be set by - setting ``SCRIPT_NAME`` in the environment or as an HTTP header. - -How can I name processes? - You need to install the Python package setproctitle_. Then you can specify - a base process name on the command line (``-n``) or in the configuration - file. - -.. _deployment: http://gunicorn.org/deployment.html -.. _slowloris: http://ha.ckers.org/slowloris/ -.. _setproctitle: http://pypi.python.org/pypi/setproctitle -.. _Eventlet: http://eventlet.net -.. _Gevent: http://gevent.org \ No newline at end of file diff --git a/doc/site/index.rst b/doc/site/index.rst index 528ea184..a551c284 100644 --- a/doc/site/index.rst +++ b/doc/site/index.rst @@ -2,7 +2,7 @@ template: index.html title: Welcome Green Unicorn -============= +------------- Gunicorn 'Green Unicorn' is a WSGI_ HTTP Server for UNIX. It's a pre-fork worker model ported from Ruby's Unicorn_ project. The Gunicorn server is diff --git a/doc/site/installation.rst b/doc/site/install.rst similarity index 81% rename from doc/site/installation.rst rename to doc/site/install.rst index 8cc7b178..c14650a4 100644 --- a/doc/site/installation.rst +++ b/doc/site/install.rst @@ -1,8 +1,9 @@ template: doc.html -title: Installing Gunicorn +title: Install -Installation -============ +.. contents:: + :class: sidebar + :backlinks: top Requirements ------------ @@ -11,8 +12,8 @@ Requirements - setuptools >= 0.6c6 - nosetests (for the test suite only) -Installing with easy_install ----------------------------- +With easy_install +----------------- If you don't already have ``easy_install`` available you'll want to download and run the ``ez_setup.py`` script:: @@ -24,44 +25,44 @@ To install or upgrade to the latest released version of Gunicorn:: $ sudo easy_install -U gunicorn -Installing from source ----------------------- +From Source +----------- You can install Gunicorn from source just as you would install any other Python package. Gunicorn uses setuptools which will automatically fetch all dependencies (including setuptools itself). -Get a Copy -++++++++++ - You can download a tarball of the latest sources from `GitHub Downloads`_ or fetch them with git_:: + # Using git: $ git clone git://github.com/benoitc/gunicorn.git + $ cd gunicorn -Installation -++++++++++++ + # Or using a tarball: + $ wget http://github.com/benoitc/gunicorn/tarball/master -o gunicorn.tar.gz + $ tar -xvzf gunicorn.tar.gz + $ cd gunicorn-$HASH/ -:: - - $ python setup.py install + # Install + $ sudo python setup.py install If you've cloned the git repository, its highly recommended that you use the ``develop`` command which will allow you to use Gunicorn from the source directory. This will allow you to keep up to date with development on GitHub as well as make changes to the source:: - $ python setup.py develop + $ python setup.py develop -Enabling async workers ----------------------- +Async Workers +------------- You may also want to install Eventlet_ or Gevent_ if you expect that your -application code may need to pause for extended periods of time during -request processing. Check out the FAQ_ for more information on when you'll +application code may need to pause for extended periods of time during request +processing. Check out the `design docs`_ for more information on when you'll want to consider one of the alternate worker types. -To install eventlet:: +:: $ easy_install -U greenlet # Required for both $ easy_install -U eventlet # For eventlet workers @@ -78,8 +79,8 @@ To install eventlet:: package manager. If Gevent_ fails to build even with ``libevent`` installed, this is the most likely reason. -Installing on Ubuntu/Debian systems ------------------------------------ +Ubuntu/Debian +------------- If you use Ubuntu_ karmic, you can update your system with packages from our PPA_ by adding ``ppa:bchesneau/gunicorn`` to your system's Software @@ -91,16 +92,22 @@ and adding them to your system's software sources:: deb http://ppa.launchpad.net/bchesneau/gunicorn/ubuntu karmic main deb-src http://ppa.launchpad.net/bchesneau/gunicorn/ubuntu karmic main -Signing key:: +Signing key ++++++++++++ + +:: 1024R/15E5EB06 -Fingerprint:: +Fingerprint ++++++++++++ + +:: 49AEEDFF5CDCD82CEA8AB4DABC981A8115E5EB06 .. _`GitHub Downloads`: http://github.com/benoitc/gunicorn/downloads -.. _FAQ: faq.html +.. _`design docs`: design.html .. _git: http://git-scm.com/ .. _Eventlet: http://eventlet.net .. _Gevent: http://gevent.org diff --git a/doc/site/news.rst b/doc/site/news.rst index 39297067..ecbdb937 100644 --- a/doc/site/news.rst +++ b/doc/site/news.rst @@ -1,9 +1,6 @@ template: doc.html title: News -News -==== - 0.9.1 / 2010-05-26 ------------------ diff --git a/doc/site/run.rst b/doc/site/run.rst new file mode 100644 index 00000000..248f5209 --- /dev/null +++ b/doc/site/run.rst @@ -0,0 +1,117 @@ +template: doc.html +title: Run + +.. contents:: + :class: sidebar + :backlinks: top + +Commands +-------- + +After installing Gunicorn you will have access to three command line scripts +that can be used for serving the various supported web frameworks: + + * ``gunicorn`` + * ``gunicorn_django`` + * ``gunicorn_paster`` + +gunicorn +++++++++ + +The first and most basic script is used to serve 'bare' WSGI applications +that don't require a translation layer. Basic usage:: + + $ gunicorn [OPTIONS] APP_MODULE + +Where ``APP_MODULE`` is of the pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. The +module name can be a full dotted path. The variable name refers to a WSGI +callable that should be found in the specified module. + +Example with test app:: + + $ cd examples + $ cat test.py + # -*- coding: utf-8 - + # + # This file is part of gunicorn released under the MIT license. + # See the NOTICE for more information. + + def app(environ, start_response): + """Simplest possible application object""" + data = 'Hello, World!\n' + status = '200 OK' + response_headers = [ + ('Content-type','text/plain'), + ('Content-Length', str(len(data))) + ] + start_response(status, response_headers) + return iter([data]) + + $ gunicorn --workers=2 test:app + +gunicorn_django ++++++++++++++++ + +You might not have guessed it, but this script is used to serve Django +applications. Basic usage:: + + $ gunicorn_django [OPTIONS] [SETTINGS_PATH] + +By default ``SETTINGS_PATH`` will look for ``settings.py`` in the current +directory. + +Example with your Django project:: + + $ cd path/to/yourdjangoproject + $ gunicorn_django --workers=2 + +gunicorn_paster ++++++++++++++++ + +Yeah, for Paster-compatible frameworks (Pylons, TurboGears 2, ...). We +apologize for the lack of script name creativity. And some usage:: + + $ gunicorn_paster [OPTIONS] paste_config.ini + +Simple example:: + + $ cd yourpasteproject + $ gunicorn_paste --workers=2 development.ini + +Integration +----------- + +Alternatively, we also provide integration for both Django and Paster +applications in case your deployment strategy would be better served by such +invocation styles. + +Django ./manage.py +++++++++++++++++++ + +You can add a ``run_gunicorn`` command to your ``./manage.py`` simply by adding +gunicorn to your ``INSTALLED_APPS``:: + + INSTALLED_APPS = ( + ... + "gunicorn", + ) + +Then you can run:: + + python manage.py run_gunicorn + +paster serve +++++++++++++ + +If you're wanting to keep on keeping on with the usual paster serve command, +you can specify the Gunicorn server settings in your configuration file:: + + [server:main] + use = egg:gunicorn#main + host = 127.0.0.1 + port = 5000 + +And then as per usual:: + + $ cd yourpasteproject + $ paster serve development.ini workers=2 diff --git a/doc/site/usage.rst b/doc/site/usage.rst deleted file mode 100644 index 82960b50..00000000 --- a/doc/site/usage.rst +++ /dev/null @@ -1,189 +0,0 @@ -template: doc.html -title: Command Line Usage - -Usage -===== - -After installing Gunicorn you will have access to three command line scripts -that can be used for serving the various supported web frameworks: ``gunicorn``, -``gunicorn_django``, and ``gunicorn_paster``. - -Commonly Used Arguments ------------------------ - - * ``-c CONFIG, --config=CONFIG`` - Specify the path to a `config file`_ - * ``-b BIND, --bind=BIND`` - Specify a server socket to bind. Server sockets - can be any of ``$(HOST)``, ``$(HOST):$(PORT)``, or ``unix:$(PATH)``. - An IP is a valid ``$(HOST)``. - * ``-w WORKERS, --workers=WORKERS`` - The number of worker processes. This - number should generally be between 2-4 workers per core in the server. - Check the FAQ_ for ideas on tuning this parameter. - * ``-k WORKERCLASS, --worker-class=WORKERCLASS`` - The type of worker process - to run. You'll definitely want to read the `production page`_ for the - implications of this parameter. You can set this to ``egg:gunicorn#$(NAME)`` - where ``$(NAME)`` is one of ``sync``, ``eventlet``, ``gevent``, or - ``tornado``. ``sync`` is the default. - * ``-n APP_NAME, --name=APP_NAME`` - If setproctitle_ is installed you can - adjust the name of Gunicorn process as they appear in the process system - table (which affects tools like ``ps`` and ``top``). - -There are various other parameters that affect user privileges, logging, etc. -You can see the complete list at the bottom of this page or as expected with:: - - $ gunicorn -h - -gunicorn --------- - -The first and most basic script is used to server 'bare' WSGI applications -that don't require a translation layer. Basic usage:: - - $ gunicorn [OPTIONS] APP_MODULE - -Where ``APP_MODULE`` is of the pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. The -module name can be a full dotted path. The variable name refers to a WSGI -callable that should be found in the specified module. - -Example with test app:: - - $ cd examples - $ gunicorn --workers=2 test:app - -gunicorn_django ---------------- - -You might not have guessed it, but this script is used to server Django -applications. Basic usage:: - - $ gunicorn_django [OPTIONS] [SETTINGS_PATH] - -By default ``SETTINGS_PATH`` will look for ``settings.py`` in the current -directory. - -Example with your Django project:: - - $ cd path/to/yourdjangoproject - $ gunicorn_django --workers=2 - -Alternatively, you can install some Gunicorn magic directly into your Django -project and use the provided command for running the server. - -First you'll need to add ``gunicorn`` to your ``INSTALLED_APPS`` in the settings -file:: - - INSTALLED_APPS = ( - ... - "gunicorn", - ) - -Then you can run:: - - python manage.py run_gunicorn - -gunicorn_paster ---------------- - -Yeah, for Paster-compatible frameworks (Pylons, TurboGears 2, ...). We -apologize for the lack of script name creativity. And some usage:: - - $ gunicorn_paster [OPTIONS] paste_config.ini - -Simple example:: - - $ cd yourpasteproject - $ gunicorn_paste --workers=2 development.ini - -If you're wanting to keep on keeping on with the usual paster serve command, -you can specify the Gunicorn server settings in your configuration file:: - - [server:main] - use = egg:gunicorn#main - host = 127.0.0.1 - port = 5000 - -And then as per usual:: - - $ cd yourpasteproject - $ paster serve development.ini workers=2 - -Full Command Line Usage ------------------------ - -:: - - $ gunicorn -h - Usage: gunicorn [OPTIONS] APP_MODULE - - Options: - -c CONFIG, --config=CONFIG - Config file. [none] - -b BIND, --bind=BIND Adress to listen on. Ex. 127.0.0.1:8000 or - unix:/tmp/gunicorn.sock - -w WORKERS, --workers=WORKERS - Number of workers to spawn. [1] - -k WORKER_CLASS, --worker-class=WORKER_CLASS - The type of request processing to use - [egg:gunicorn#sync] - -p PIDFILE, --pid=PIDFILE - set the background PID FILE - -D, --daemon Run daemonized in the background. - -m UMASK, --umask=UMASK - Define umask of daemon process - -u USER, --user=USER Change worker user - -g GROUP, --group=GROUP - Change worker group - -n PROC_NAME, --name=PROC_NAME - Process name - --log-level=LOGLEVEL Log level below which to silence messages. [info] - --log-file=LOGFILE Log to a file. - equals stdout. [-] - --debug Debug mode. only 1 worker. - --spew Install a trace hook - --version show program's version number and exit - -h, --help show this help message and exit - -Framework Examples ------------------- - -This is an incomplete list of examples of using Gunicorn with various -Python web frameworks. If you have an example to add you're very much -invited to submit a ticket to the `issue tracker`_ to have it included. - -Itty -++++ - -Itty comes with builtin Gunicorn support. The Itty "Hello, world!" looks -like such:: - - from itty import * - - @get('/') - def index(request): - return 'Hello World!' - - run_itty(server='gunicorn') - -Flask -+++++ - -Flask applications are WSGI compatible. Given this Flask app in an importable -Python module "helloflask.py":: - - from flask import Flask - app = Flask(__name__) - - @app.route("/") - def hello(): - return "Hello World!" - -Gunicorn can then be used to run it as such:: - - $ gunicorn helloflask:app - -Remember, if you're just trying to get things up and runnign that "importable" -can be as simple as "exists in the current directory". - -.. _FAQ: faq.html -.. _`production page`: deployment.html -.. _`config file`: configuration.html -.. _setproctitle: http://pypi.python.org/pypi/setproctitle/ -.. _`issue tracker`: http://github.com/benoitc/gunicorn/issues diff --git a/doc/templates/base.html b/doc/templates/base.html index 7f7f1fbd..7182a8a0 100644 --- a/doc/templates/base.html +++ b/doc/templates/base.html @@ -4,40 +4,34 @@ Green Unicorn - {% block title %}Welcome{% endblock %} - - - - + -
    - - {% block extra %}{% endblock %} - {% block body %}{% endblock %} - diff --git a/doc/templates/doc.html b/doc/templates/doc.html index 1c2b150f..67752fe0 100644 --- a/doc/templates/doc.html +++ b/doc/templates/doc.html @@ -1,11 +1,4 @@ {% extends "base.html" %} - {% block title %}{{ title }}{% endblock %} - -{% block body %} - - {% include "menu.html" %} - - {{ body }} - -{% endblock %} \ No newline at end of file +{% block toc %}{{ toc }}{% endblock %} +{% block body %}{{ body }}{% endblock %} \ No newline at end of file diff --git a/doc/templates/index.html b/doc/templates/index.html index a465b837..8e9f3682 100644 --- a/doc/templates/index.html +++ b/doc/templates/index.html @@ -1,8 +1,2 @@ {% extends "base.html" %} - -{% block body %}{{ body }}{% endblock %} - -{% block extra %} - {% include "menu.html" %} -{% endblock %} - +{% block body %}{{ body }}{% endblock %} \ No newline at end of file diff --git a/doc/templates/menu.html b/doc/templates/menu.html deleted file mode 100644 index 795eea8e..00000000 --- a/doc/templates/menu.html +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/examples/cherryapp.py b/examples/frameworks/cherryapp.py similarity index 100% rename from examples/cherryapp.py rename to examples/frameworks/cherryapp.py diff --git a/examples/djangotest/__init__.py b/examples/frameworks/djangotest/__init__.py similarity index 100% rename from examples/djangotest/__init__.py rename to examples/frameworks/djangotest/__init__.py diff --git a/examples/djangotest/manage.py b/examples/frameworks/djangotest/manage.py similarity index 100% rename from examples/djangotest/manage.py rename to examples/frameworks/djangotest/manage.py diff --git a/examples/djangotest/settings.py b/examples/frameworks/djangotest/settings.py similarity index 100% rename from examples/djangotest/settings.py rename to examples/frameworks/djangotest/settings.py diff --git a/examples/djangotest/testing/__init__.py b/examples/frameworks/djangotest/testing/__init__.py similarity index 100% rename from examples/djangotest/testing/__init__.py rename to examples/frameworks/djangotest/testing/__init__.py diff --git a/examples/djangotest/testing/models.py b/examples/frameworks/djangotest/testing/models.py similarity index 100% rename from examples/djangotest/testing/models.py rename to examples/frameworks/djangotest/testing/models.py diff --git a/examples/djangotest/testing/templates/base.html b/examples/frameworks/djangotest/testing/templates/base.html similarity index 100% rename from examples/djangotest/testing/templates/base.html rename to examples/frameworks/djangotest/testing/templates/base.html diff --git a/examples/djangotest/testing/templates/home.html b/examples/frameworks/djangotest/testing/templates/home.html similarity index 100% rename from examples/djangotest/testing/templates/home.html rename to examples/frameworks/djangotest/testing/templates/home.html diff --git a/examples/djangotest/testing/tests.py b/examples/frameworks/djangotest/testing/tests.py similarity index 100% rename from examples/djangotest/testing/tests.py rename to examples/frameworks/djangotest/testing/tests.py diff --git a/examples/djangotest/testing/urls.py b/examples/frameworks/djangotest/testing/urls.py similarity index 100% rename from examples/djangotest/testing/urls.py rename to examples/frameworks/djangotest/testing/urls.py diff --git a/examples/djangotest/testing/views.py b/examples/frameworks/djangotest/testing/views.py similarity index 100% rename from examples/djangotest/testing/views.py rename to examples/frameworks/djangotest/testing/views.py diff --git a/examples/djangotest/urls.py b/examples/frameworks/djangotest/urls.py similarity index 100% rename from examples/djangotest/urls.py rename to examples/frameworks/djangotest/urls.py diff --git a/examples/frameworks/flaskapp.py b/examples/frameworks/flaskapp.py new file mode 100644 index 00000000..aabe86fd --- /dev/null +++ b/examples/frameworks/flaskapp.py @@ -0,0 +1,11 @@ +# Run with: +# +# $ gunicorn flaskapp:app +# + +from flask import Flask +app = Flask(__name__) + +@app.route("/") +def hello(): + return "Hello World!" diff --git a/examples/frameworks/ittyapp.py b/examples/frameworks/ittyapp.py new file mode 100644 index 00000000..d2f26a16 --- /dev/null +++ b/examples/frameworks/ittyapp.py @@ -0,0 +1,12 @@ +# Run with: +# +# $ python ittyapp.py +# + +from itty import * + +@get('/') +def index(request): + return 'Hello World!' + +run_itty(server='gunicorn') diff --git a/examples/pylonstest/MANIFEST.in b/examples/frameworks/pylonstest/MANIFEST.in similarity index 100% rename from examples/pylonstest/MANIFEST.in rename to examples/frameworks/pylonstest/MANIFEST.in diff --git a/examples/pylonstest/README.txt b/examples/frameworks/pylonstest/README.txt similarity index 100% rename from examples/pylonstest/README.txt rename to examples/frameworks/pylonstest/README.txt diff --git a/examples/pylonstest/development.ini b/examples/frameworks/pylonstest/development.ini similarity index 100% rename from examples/pylonstest/development.ini rename to examples/frameworks/pylonstest/development.ini diff --git a/examples/pylonstest/docs/index.txt b/examples/frameworks/pylonstest/docs/index.txt similarity index 100% rename from examples/pylonstest/docs/index.txt rename to examples/frameworks/pylonstest/docs/index.txt diff --git a/examples/pylonstest/ez_setup.py b/examples/frameworks/pylonstest/ez_setup.py similarity index 100% rename from examples/pylonstest/ez_setup.py rename to examples/frameworks/pylonstest/ez_setup.py diff --git a/examples/pylonstest/nose.ini b/examples/frameworks/pylonstest/nose.ini similarity index 100% rename from examples/pylonstest/nose.ini rename to examples/frameworks/pylonstest/nose.ini diff --git a/examples/pylonstest/pylonstest/__init__.py b/examples/frameworks/pylonstest/pylonstest/__init__.py similarity index 100% rename from examples/pylonstest/pylonstest/__init__.py rename to examples/frameworks/pylonstest/pylonstest/__init__.py diff --git a/examples/pylonstest/pylonstest/config/__init__.py b/examples/frameworks/pylonstest/pylonstest/config/__init__.py similarity index 100% rename from examples/pylonstest/pylonstest/config/__init__.py rename to examples/frameworks/pylonstest/pylonstest/config/__init__.py diff --git a/examples/pylonstest/pylonstest/config/deployment.ini_tmpl b/examples/frameworks/pylonstest/pylonstest/config/deployment.ini_tmpl similarity index 100% rename from examples/pylonstest/pylonstest/config/deployment.ini_tmpl rename to examples/frameworks/pylonstest/pylonstest/config/deployment.ini_tmpl diff --git a/examples/pylonstest/pylonstest/config/environment.py b/examples/frameworks/pylonstest/pylonstest/config/environment.py similarity index 100% rename from examples/pylonstest/pylonstest/config/environment.py rename to examples/frameworks/pylonstest/pylonstest/config/environment.py diff --git a/examples/pylonstest/pylonstest/config/middleware.py b/examples/frameworks/pylonstest/pylonstest/config/middleware.py similarity index 100% rename from examples/pylonstest/pylonstest/config/middleware.py rename to examples/frameworks/pylonstest/pylonstest/config/middleware.py diff --git a/examples/pylonstest/pylonstest/config/routing.py b/examples/frameworks/pylonstest/pylonstest/config/routing.py similarity index 100% rename from examples/pylonstest/pylonstest/config/routing.py rename to examples/frameworks/pylonstest/pylonstest/config/routing.py diff --git a/examples/pylonstest/pylonstest/controllers/__init__.py b/examples/frameworks/pylonstest/pylonstest/controllers/__init__.py similarity index 100% rename from examples/pylonstest/pylonstest/controllers/__init__.py rename to examples/frameworks/pylonstest/pylonstest/controllers/__init__.py diff --git a/examples/pylonstest/pylonstest/controllers/error.py b/examples/frameworks/pylonstest/pylonstest/controllers/error.py similarity index 100% rename from examples/pylonstest/pylonstest/controllers/error.py rename to examples/frameworks/pylonstest/pylonstest/controllers/error.py diff --git a/examples/pylonstest/pylonstest/controllers/hello.py b/examples/frameworks/pylonstest/pylonstest/controllers/hello.py similarity index 100% rename from examples/pylonstest/pylonstest/controllers/hello.py rename to examples/frameworks/pylonstest/pylonstest/controllers/hello.py diff --git a/examples/pylonstest/pylonstest/lib/__init__.py b/examples/frameworks/pylonstest/pylonstest/lib/__init__.py similarity index 100% rename from examples/pylonstest/pylonstest/lib/__init__.py rename to examples/frameworks/pylonstest/pylonstest/lib/__init__.py diff --git a/examples/pylonstest/pylonstest/lib/app_globals.py b/examples/frameworks/pylonstest/pylonstest/lib/app_globals.py similarity index 100% rename from examples/pylonstest/pylonstest/lib/app_globals.py rename to examples/frameworks/pylonstest/pylonstest/lib/app_globals.py diff --git a/examples/pylonstest/pylonstest/lib/base.py b/examples/frameworks/pylonstest/pylonstest/lib/base.py similarity index 100% rename from examples/pylonstest/pylonstest/lib/base.py rename to examples/frameworks/pylonstest/pylonstest/lib/base.py diff --git a/examples/pylonstest/pylonstest/lib/helpers.py b/examples/frameworks/pylonstest/pylonstest/lib/helpers.py similarity index 100% rename from examples/pylonstest/pylonstest/lib/helpers.py rename to examples/frameworks/pylonstest/pylonstest/lib/helpers.py diff --git a/examples/pylonstest/pylonstest/model/__init__.py b/examples/frameworks/pylonstest/pylonstest/model/__init__.py similarity index 100% rename from examples/pylonstest/pylonstest/model/__init__.py rename to examples/frameworks/pylonstest/pylonstest/model/__init__.py diff --git a/examples/pylonstest/pylonstest/public/bg.png b/examples/frameworks/pylonstest/pylonstest/public/bg.png similarity index 100% rename from examples/pylonstest/pylonstest/public/bg.png rename to examples/frameworks/pylonstest/pylonstest/public/bg.png diff --git a/examples/pylonstest/pylonstest/public/favicon.ico b/examples/frameworks/pylonstest/pylonstest/public/favicon.ico similarity index 100% rename from examples/pylonstest/pylonstest/public/favicon.ico rename to examples/frameworks/pylonstest/pylonstest/public/favicon.ico diff --git a/examples/pylonstest/pylonstest/public/index.html b/examples/frameworks/pylonstest/pylonstest/public/index.html similarity index 100% rename from examples/pylonstest/pylonstest/public/index.html rename to examples/frameworks/pylonstest/pylonstest/public/index.html diff --git a/examples/pylonstest/pylonstest/public/pylons-logo.gif b/examples/frameworks/pylonstest/pylonstest/public/pylons-logo.gif similarity index 100% rename from examples/pylonstest/pylonstest/public/pylons-logo.gif rename to examples/frameworks/pylonstest/pylonstest/public/pylons-logo.gif diff --git a/examples/pylonstest/pylonstest/tests/__init__.py b/examples/frameworks/pylonstest/pylonstest/tests/__init__.py similarity index 100% rename from examples/pylonstest/pylonstest/tests/__init__.py rename to examples/frameworks/pylonstest/pylonstest/tests/__init__.py diff --git a/examples/pylonstest/pylonstest/tests/functional/__init__.py b/examples/frameworks/pylonstest/pylonstest/tests/functional/__init__.py similarity index 100% rename from examples/pylonstest/pylonstest/tests/functional/__init__.py rename to examples/frameworks/pylonstest/pylonstest/tests/functional/__init__.py diff --git a/examples/pylonstest/pylonstest/tests/functional/test_hello.py b/examples/frameworks/pylonstest/pylonstest/tests/functional/test_hello.py similarity index 100% rename from examples/pylonstest/pylonstest/tests/functional/test_hello.py rename to examples/frameworks/pylonstest/pylonstest/tests/functional/test_hello.py diff --git a/examples/pylonstest/pylonstest/tests/test_models.py b/examples/frameworks/pylonstest/pylonstest/tests/test_models.py similarity index 100% rename from examples/pylonstest/pylonstest/tests/test_models.py rename to examples/frameworks/pylonstest/pylonstest/tests/test_models.py diff --git a/examples/pylonstest/pylonstest/websetup.py b/examples/frameworks/pylonstest/pylonstest/websetup.py similarity index 100% rename from examples/pylonstest/pylonstest/websetup.py rename to examples/frameworks/pylonstest/pylonstest/websetup.py diff --git a/examples/pylonstest/setup.cfg b/examples/frameworks/pylonstest/setup.cfg similarity index 100% rename from examples/pylonstest/setup.cfg rename to examples/frameworks/pylonstest/setup.cfg diff --git a/examples/pylonstest/setup.py b/examples/frameworks/pylonstest/setup.py similarity index 100% rename from examples/pylonstest/setup.py rename to examples/frameworks/pylonstest/setup.py diff --git a/examples/pylonstest/test.ini b/examples/frameworks/pylonstest/test.ini similarity index 100% rename from examples/pylonstest/test.ini rename to examples/frameworks/pylonstest/test.ini diff --git a/examples/tornado/basic.py b/examples/frameworks/tornadoapp.py similarity index 81% rename from examples/tornado/basic.py rename to examples/frameworks/tornadoapp.py index 3c4df96a..6c6781ce 100644 --- a/examples/tornado/basic.py +++ b/examples/frameworks/tornadoapp.py @@ -3,6 +3,10 @@ # This file is part of gunicorn released under the MIT license. # See the NOTICE for more information. # +# Run with: +# +# $ gunicorn -k egg:gunicorn#tornado tornadoapp:app +# import tornado.web diff --git a/gunicorn/config.py b/gunicorn/config.py index 2a89f848..b4be3c1f 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -197,7 +197,7 @@ def validate_callable(arity): return _validate_callable with Setting("config") as s: - s.section = "Config" + s.section = "Config File" s.cli = ["-c", "--config"] s.meta = "FILE" s.validator = validate_string @@ -205,9 +205,6 @@ with Setting("config") as s: s.fmt_desc("""\ The path to a Gunicorn config file. - By default Gunicorn will try to read a file named 'gunicorn.conf.py' in - the current directory. - Only has an effect when specified on the command line or as part of an application specific configuration. """) @@ -268,7 +265,7 @@ with Setting("worker_class") as s: The type of workers to use. The default async class should handle most 'normal' types of work loads. - You'll want to read http://gunicorn/deployment.hml for information on + You'll want to read http://gunicorn.org/design.hml for information on when you might want to choose one of the other worker classes. An string referring to a 'gunicorn.workers' entry point or a @@ -277,10 +274,10 @@ with Setting("worker_class") as s: The default provided values are: - * egg:gunicorn#sync - * egg:gunicorn#eventlet - Requires eventlet >= 0.9.7 - * egg:gunicorn#gevent - Requires gevent >= 0.12.2 (?) - * egg:gunicorn#tornado - Requires tornado >= 0.2 + * ``egg:gunicorn#sync`` + * ``egg:gunicorn#eventlet`` - Requires eventlet >= 0.9.7 + * ``egg:gunicorn#gevent`` - Requires gevent >= 0.12.2 (?) + * ``egg:gunicorn#tornado`` - Requires tornado >= 0.2 """) with Setting("worker_connections") as s: @@ -393,27 +390,29 @@ with Setting("pidfile") as s: with Setting("user") as s: s.section = "Server Mechanics" s.cli = ["-u", "--user"] + s.meta = "USER" s.validator = validate_string s.default = None s.fmt_desc("""\ Switch worker processes to run as this user. A valid user id (as an integer) or the name of a user that can be - retrieved with a call to pwd.getpwnam(value) or None to not change the - worker process user. + retrieved with a call to pwd.getpwnam(value) or None to not change + the worker process user. """) with Setting("group") as s: s.section = "Server Mechanics" s.cli = ["-g", "--group"] + s.meta = "GROUP" s.validator = validate_string s.default = None s.fmt_desc("""\ Switch worker process to run as this group. A valid group id (as an integer) or the name of a user that can be - retrieved with a call to pwd.getgrnam(value) or None to change the - worker processes group. + retrieved with a call to pwd.getgrnam(value) or None to not change + the worker processes group. """) with Setting("umask") as s: @@ -487,9 +486,10 @@ with Setting("proc_name") as s: s.fmt_desc("""\ A base to use with setproctitle for process naming. - This affects things like 'ps' and 'top'. If you're going to be running - more than one instance of Gunicorn you'll probably want to set a name to - tell them apart. This requires that you install the setproctitle module. + This affects things like ``ps`` and ``top``. If you're going to be + running more than one instance of Gunicorn you'll probably want to set a + name to tell them apart. This requires that you install the setproctitle + module. It defaults to 'gunicorn'. """)