diff --git a/gunicorn/arbiter.py b/gunicorn/arbiter.py index 459551a7..1a3f5bbf 100644 --- a/gunicorn/arbiter.py +++ b/gunicorn/arbiter.py @@ -14,7 +14,7 @@ import sys import time import traceback -from gunicorn.errors import HaltServer +from gunicorn.errors import HaltServer, AppImportError from gunicorn.pidfile import Pidfile from gunicorn.sock import create_sockets from gunicorn import util @@ -34,6 +34,9 @@ class Arbiter(object): # this error code, the arbiter will terminate. WORKER_BOOT_ERROR = 3 + # A flag indicating if an application failed to be loaded + APP_LOAD_ERROR = 4 + START_CTX = {} LISTENERS = [] @@ -435,6 +438,9 @@ class Arbiter(object): if exitcode == self.WORKER_BOOT_ERROR: reason = "Worker failed to boot." 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) if not worker: continue @@ -478,6 +484,13 @@ class Arbiter(object): sys.exit(0) except SystemExit: 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: self.log.exception("Exception in worker process:\n%s", traceback.format_exc()) diff --git a/gunicorn/errors.py b/gunicorn/errors.py index aff95798..7465edb8 100644 --- a/gunicorn/errors.py +++ b/gunicorn/errors.py @@ -15,3 +15,7 @@ class HaltServer(BaseException): class ConfigError(BaseException): """ Exception raised on config error """ + + +class AppImportError(Exception): + """ Exception raised when loading an application """ diff --git a/gunicorn/util.py b/gunicorn/util.py index 457b9e1b..4216bf8d 100644 --- a/gunicorn/util.py +++ b/gunicorn/util.py @@ -18,6 +18,7 @@ import inspect import errno import warnings +from gunicorn.errors import AppImportError from gunicorn.six import text_type, string_types MAXFD = 1024 @@ -358,11 +359,17 @@ def import_app(module): raise 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: - raise ImportError("Failed to find application object: %r" % obj) + raise AppImportError("Failed to find application object: %r" % obj) + if not callable(app): - raise TypeError("Application object must be callable.") + raise AppImportError("Application object must be callable.") return app