make sure we exit immediately if we fail to load the application.

While I'm here describe a more accurate error when it happens.

fix #508
This commit is contained in:
benoitc 2013-04-22 18:42:29 +02:00
parent 3ade8e8d78
commit 612f4125dd
3 changed files with 28 additions and 4 deletions

View File

@ -14,7 +14,7 @@ import sys
import time import time
import traceback import traceback
from gunicorn.errors import HaltServer from gunicorn.errors import HaltServer, AppImportError
from gunicorn.pidfile import Pidfile from gunicorn.pidfile import Pidfile
from gunicorn.sock import create_sockets from gunicorn.sock import create_sockets
from gunicorn import util from gunicorn import util
@ -34,6 +34,9 @@ class Arbiter(object):
# this error code, the arbiter will terminate. # this error code, the arbiter will terminate.
WORKER_BOOT_ERROR = 3 WORKER_BOOT_ERROR = 3
# A flag indicating if an application failed to be loaded
APP_LOAD_ERROR = 4
START_CTX = {} START_CTX = {}
LISTENERS = [] LISTENERS = []
@ -435,6 +438,9 @@ class Arbiter(object):
if exitcode == self.WORKER_BOOT_ERROR: if exitcode == self.WORKER_BOOT_ERROR:
reason = "Worker failed to boot." reason = "Worker failed to boot."
raise HaltServer(reason, self.WORKER_BOOT_ERROR) raise HaltServer(reason, self.WORKER_BOOT_ERROR)
if exitcode == self.APP_LOAD_ERROR:
reason = "App failed to load."
raise HaltServer(reason, self.APP_LOAD_ERROR)
worker = self.WORKERS.pop(wpid, None) worker = self.WORKERS.pop(wpid, None)
if not worker: if not worker:
continue continue
@ -478,6 +484,13 @@ class Arbiter(object):
sys.exit(0) sys.exit(0)
except SystemExit: except SystemExit:
raise raise
except AppImportError as e:
self.log.debug("Exception while loading the application: \n%s",
traceback.format_exc())
sys.stderr.write("%s\n" % e)
sys.stderr.flush()
sys.exit(self.APP_LOAD_ERROR)
except: except:
self.log.exception("Exception in worker process:\n%s", self.log.exception("Exception in worker process:\n%s",
traceback.format_exc()) traceback.format_exc())

View File

@ -15,3 +15,7 @@ class HaltServer(BaseException):
class ConfigError(BaseException): class ConfigError(BaseException):
""" Exception raised on config error """ """ Exception raised on config error """
class AppImportError(Exception):
""" Exception raised when loading an application """

View File

@ -18,6 +18,7 @@ import inspect
import errno import errno
import warnings import warnings
from gunicorn.errors import AppImportError
from gunicorn.six import text_type, string_types from gunicorn.six import text_type, string_types
MAXFD = 1024 MAXFD = 1024
@ -358,11 +359,17 @@ def import_app(module):
raise raise
mod = sys.modules[module] mod = sys.modules[module]
app = eval(obj, mod.__dict__)
try:
app = eval(obj, mod.__dict__)
except NameError:
raise AppImportError("Failed to find application: %r" % module)
if app is None: if app is None:
raise ImportError("Failed to find application object: %r" % obj) raise AppImportError("Failed to find application object: %r" % obj)
if not callable(app): if not callable(app):
raise TypeError("Application object must be callable.") raise AppImportError("Application object must be callable.")
return app return app