From db1c70a44edcb2ba5d5f349b9942a1edb6b88f87 Mon Sep 17 00:00:00 2001 From: benoitc Date: Tue, 25 May 2010 15:13:33 +0200 Subject: [PATCH 1/5] fix issue #59. --- gunicorn/sock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gunicorn/sock.py b/gunicorn/sock.py index 3b913588..27dde042 100644 --- a/gunicorn/sock.py +++ b/gunicorn/sock.py @@ -74,7 +74,7 @@ class UnixSocket(BaseSocket): return "unix:%s" % self.address def bind(self, sock): - old_umask = os.umask(self.conf['umask']) + old_umask = os.umask(self.conf.umask) sock.bind(self.address) util.chown(self.address, self.conf.uid, self.conf.gid) os.umask(old_umask) From 2f1c9177aacc136273fb17563e371fad7613f14d Mon Sep 17 00:00:00 2001 From: "Paul J. Davis" Date: Tue, 25 May 2010 13:03:35 -0400 Subject: [PATCH 2/5] Allow for pidfiles in $CWD --- gunicorn/pidfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gunicorn/pidfile.py b/gunicorn/pidfile.py index 0b8f00be..bbdf1456 100644 --- a/gunicorn/pidfile.py +++ b/gunicorn/pidfile.py @@ -33,7 +33,7 @@ class Pidfile(object): # Write pidfile fdir = os.path.dirname(self.fname) - if not os.path.isdir(fdir): + if fdir and not os.path.isdir(fdir): raise RuntimeError("%s doesn't exist. Can't create pidfile." % fdir) fd, fname = tempfile.mkstemp(dir=fdir) os.write(fd, "%s\n" % self.pid) From 767dc16544b9807c32cf2728b18b869112c6be1f Mon Sep 17 00:00:00 2001 From: benoitc Date: Wed, 26 May 2010 00:32:59 +0200 Subject: [PATCH 3/5] remove -d option and update doc. --- doc/htdocs/news.html | 36 ++++++++++++-------- doc/htdocs/usage.html | 2 +- doc/site/news.rst | 11 ++++-- doc/site/usage.rst | 2 +- gunicorn/config.py | 2 +- gunicorn/management/commands/run_gunicorn.py | 2 +- 6 files changed, 35 insertions(+), 20 deletions(-) diff --git a/doc/htdocs/news.html b/doc/htdocs/news.html index dbe5f9ba..7d4b29fd 100644 --- a/doc/htdocs/news.html +++ b/doc/htdocs/news.html @@ -50,7 +50,15 @@

News

-

0.9.0 2010-05-22

+

0.9.1 / 2010-05-26

+
    +
  • Fix configuration
  • +
  • Remove -d options which was used instead of -D for daemon.
  • +
  • Fix umask in unix socket
  • +
+
+
+

0.9.0 / 2010-05-24

  • Added when_ready hook. Called just after the server is started
  • Added preload setting. Load application code before the worker processes @@ -62,7 +70,7 @@ are forked.
  • Documentation improvements
-
+

0.8.1 / 2010-04-29

  • Fix builtins import in config
  • @@ -71,7 +79,7 @@ are forked.
  • Delay application loading until after processing all configuration
-
+

0.8.0 / 2010-04-22

  • Refactored Worker management for better async support. Now use the -k option @@ -79,7 +87,7 @@ to set the type of request processing to use
  • Added support for Tornado
-
+

0.7.2 / 2010-04-15

  • Added --spew option to help debugging (installs a system trace hook)
  • @@ -87,13 +95,13 @@ to set the type of request processing to use
  • Fix a bug in start_response on error
-
+

0.7.1 / 2010-04-01

  • Fix bug when responses have no body.
-
+

0.7.0 / 2010-03-26

  • Added support for Eventlet and Gevent based workers.
  • @@ -103,28 +111,28 @@ to set the type of request processing to use
  • Fix PEP 333 compliance for the write callable.
-
+

0.6.5 / 2010-03-11

  • Fix pidfile handling
  • Fix Exception Error
-
+

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

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

0.6.2 / 2010-03-01

  • Added support for chunked response.
  • @@ -135,7 +143,7 @@ temporary data.
  • Workers are now murdered by age (the oldest is killed first).
-
+

0.6.1 / 2010-02-24

  • Added gunicorn config file support for Django admin command
  • @@ -143,7 +151,7 @@ temporary data.
  • Removed TTIN/TTOU from workers which blocked other signals.
-
+

0.6 / 2010-02-22

  • Added setproctitle support
  • @@ -151,14 +159,14 @@ temporary data. permissions, new uid/gid permissions are only set for workers.
-
+

0.5.1 / 2010-02-22

  • Fix umask
  • Added Debian packaging
-
+

0.5 / 2010-02-20

  • Added configuration file handler.
  • diff --git a/doc/htdocs/usage.html b/doc/htdocs/usage.html index f2843163..d3e3e9ad 100644 --- a/doc/htdocs/usage.html +++ b/doc/htdocs/usage.html @@ -178,7 +178,7 @@ Options: Process name --log-level=LOGLEVEL Log level below which to silence messages. [info] --log-file=LOGFILE Log to a file. - equals stdout. [-] - -d, --debug Debug mode. only 1 worker. + --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 diff --git a/doc/site/news.rst b/doc/site/news.rst index 5f6a3f1a..2b31c88e 100644 --- a/doc/site/news.rst +++ b/doc/site/news.rst @@ -4,8 +4,15 @@ title: News News ==== -0.9.0 2010-05-22 ----------------- +0.9.1 / 2010-05-26 +------------------ + +- Fix configuration +- Remove -d options which was used instead of -D for daemon. +- Fix umask in unix socket + +0.9.0 / 2010-05-24 +------------------ - Added *when_ready* hook. Called just after the server is started - Added *preload* setting. Load application code before the worker processes diff --git a/doc/site/usage.rst b/doc/site/usage.rst index d771fcc5..82960b50 100644 --- a/doc/site/usage.rst +++ b/doc/site/usage.rst @@ -136,7 +136,7 @@ Full Command Line Usage Process name --log-level=LOGLEVEL Log level below which to silence messages. [info] --log-file=LOGFILE Log to a file. - equals stdout. [-] - -d, --debug Debug mode. only 1 worker. + --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 diff --git a/gunicorn/config.py b/gunicorn/config.py index b0553016..2a89f848 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -327,7 +327,7 @@ with Setting("keepalive") as s: with Setting("debug") as s: s.section = "Debugging" - s.cli = ["-d", "--debug"] + s.cli = ["--debug"] s.validator = validate_bool s.action = "store_true" s.default = False diff --git a/gunicorn/management/commands/run_gunicorn.py b/gunicorn/management/commands/run_gunicorn.py index ca798cb3..dd599f9b 100644 --- a/gunicorn/management/commands/run_gunicorn.py +++ b/gunicorn/management/commands/run_gunicorn.py @@ -52,7 +52,7 @@ class Command(BaseCommand): options['bind'] = addrport or '127.0.0.1' - options['default_proc_name'] =settings.SETTINGS_MODULE + options['default_proc_name'] = settings.SETTINGS_MODULE admin_media_path = options.pop('admin_media_path', '') quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C' From b23b64badfe2db0b63e0ca20ae2a101a7f4b49b3 Mon Sep 17 00:00:00 2001 From: benoitc Date: Wed, 26 May 2010 00:33:29 +0200 Subject: [PATCH 4/5] bump version --- gunicorn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gunicorn/__init__.py b/gunicorn/__init__.py index 95ec059e..20f9c238 100644 --- a/gunicorn/__init__.py +++ b/gunicorn/__init__.py @@ -3,5 +3,5 @@ # This file is part of gunicorn released under the MIT license. # See the NOTICE for more information. -version_info = (0, 9, 0) +version_info = (0, 9, 1) __version__ = ".".join(map(str, version_info)) From 12f8215e0437d9cff2f9365963aafe923a17b718 Mon Sep 17 00:00:00 2001 From: "Paul J. Davis" Date: Tue, 25 May 2010 19:54:33 -0400 Subject: [PATCH 5/5] Avoid infinite loops spawning workers. I noticed with preload that if a worker fails to boot the arbiter will dutifully respawn it. Only to watch it die again. This patch makes it so if a worker process exits before making it to the run loop the process will exit with a special exit code. When the arbiter sees this flag it will shutdown all processes assuming there is an unrecoverable error. --- gunicorn/app/wsgiapp.py | 7 +------ gunicorn/arbiter.py | 19 ++++++++++++++++--- gunicorn/workers/base.py | 4 +++- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/gunicorn/app/wsgiapp.py b/gunicorn/app/wsgiapp.py index c4911a2f..632fdcf7 100644 --- a/gunicorn/app/wsgiapp.py +++ b/gunicorn/app/wsgiapp.py @@ -22,9 +22,4 @@ class WSGIApplication(Application): sys.path.insert(0, os.getcwd()) def load(self): - try: - return util.import_app(self.app_uri) - except: - print "Failed to import application: %s" % self.app_uri - traceback.print_exc() - sys.exit(1) + return util.import_app(self.app_uri) diff --git a/gunicorn/arbiter.py b/gunicorn/arbiter.py index ddf32f75..5976357c 100644 --- a/gunicorn/arbiter.py +++ b/gunicorn/arbiter.py @@ -24,7 +24,12 @@ class Arbiter(object): kills them if needed. It also manages application reloading via SIGHUP/USR2. """ - + + # A flag indicating if a worker failed to + # to boot. If a worker process exist with + # this error code, the arbiter will terminate. + WORKER_BOOT_ERROR = 3 + START_CTX = {} LISTENER = None @@ -322,10 +327,16 @@ class Arbiter(object): try: while True: wpid, status = os.waitpid(-1, os.WNOHANG) - if not wpid: break + if not wpid: + break if self.reexec_pid == wpid: self.reexec_pid = 0 else: + # A worker said it cannot boot. We'll shutdown + # to avoid infinite start/stop cycles. + exitcode = status >> 8 + if exitcode == self.WORKER_BOOT_ERROR: + raise StopIteration worker = self.WORKERS.pop(wpid, None) if not worker: continue @@ -380,7 +391,9 @@ class Arbiter(object): except SystemExit: raise except: - self.log.exception("Exception in worker process.") + self.log.exception("Exception in worker process:") + if not worker.booted: + sys.exit(self.WORKER_BOOT_ERROR) sys.exit(-1) finally: self.log.info("Worker exiting (pid: %s)" % worker_pid) diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py index 5bd31ea9..cf2d52d4 100644 --- a/gunicorn/workers/base.py +++ b/gunicorn/workers/base.py @@ -33,7 +33,8 @@ class Worker(object): self.app = app self.timeout = timeout self.cfg = cfg - + self.booted = False + self.nr = 0 self.alive = True self.spinner = 0 @@ -94,6 +95,7 @@ class Worker(object): self.wsgi = self.app.wsgi() # Enter main run loop + self.booted = True self.run() def init_signals(self):