美文网首页
一次tornado升级导致的bug,排查了好久,比较坑

一次tornado升级导致的bug,排查了好久,比较坑

作者: 潇湘浅唱 | 来源:发表于2017-09-11 19:42 被阅读0次

    之前一直稳定运行的代码,我引进新项目的时候,忽然报错

    'Application' object has no attribute 'handlers'"

    困扰许久。而且是时而正常,时而出错。

    无法忍受,后开启debug模式排查,发现原来是tornado4.5起升级了,引入了新的tornado.routing模块。

    4.4的Application代码如下:

    class Application(httputil.HTTPServerConnectionDelegate):

    """A collection of request handlers that make up a web application.

    ``static_handler_class`` setting.

    """

    def __init__(self, handlers=None, default_host="", transforms=None,

    **settings):

    if transforms is None:

    self.transforms = []

    if settings.get("compress_response") or settings.get("gzip"):

    self.transforms.append(GZipContentEncoding)

    else:

    self.transforms = transforms

    self.handlers = []

    self.named_handlers = {}

    self.default_host = default_host

    self.settings = settings

    self.ui_modules = {'linkify': _linkify,

    'xsrf_form_html': _xsrf_form_html,

    'Template': TemplateModule,

    }

    self.ui_methods = {}

    self._load_ui_modules(settings.get("ui_modules", {}))

    self._load_ui_methods(settings.get("ui_methods", {}))

    if self.settings.get("static_path"):

    path = self.settings["static_path"]

    handlers = list(handlers or [])

    static_url_prefix = settings.get("static_url_prefix",

    "/static/")

    static_handler_class = settings.get("static_handler_class",

    StaticFileHandler)

    static_handler_args = settings.get("static_handler_args", {})

    static_handler_args['path'] = path

    for pattern in [re.escape(static_url_prefix) + r"(.*)",

    r"/(favicon\.ico)", r"/(robots\.txt)"]:

    handlers.insert(0, (pattern, static_handler_class,

    static_handler_args))

    if handlers:

    self.add_handlers(".*$", handlers)

    if self.settings.get('debug'):

    self.settings.setdefault('autoreload', True)

    self.settings.setdefault('compiled_template_cache', False)

    self.settings.setdefault('static_hash_cache', False)

    self.settings.setdefault('serve_traceback', True)

    # Automatically reload modified modules

    if self.settings.get('autoreload'):

    from tornado import autoreload

    autoreload.start()

    到4.5代码已经变成:

    class Application(ReversibleRouter):

    """A collection of request handlers that make up a web application.

    .. versionchanged:: 4.5

    Integration with the new `tornado.routing` module.

    """

    def __init__(self, handlers=None, default_host=None, transforms=None,

    **settings):

    if transforms is None:

    self.transforms = []

    if settings.get("compress_response") or settings.get("gzip"):

    self.transforms.append(GZipContentEncoding)

    else:

    self.transforms = transforms

    self.default_host = default_host

    self.settings = settings

    self.ui_modules = {'linkify': _linkify,

    'xsrf_form_html': _xsrf_form_html,

    'Template': TemplateModule,

    }

    self.ui_methods = {}

    self._load_ui_modules(settings.get("ui_modules", {}))

    self._load_ui_methods(settings.get("ui_methods", {}))

    if self.settings.get("static_path"):

    path = self.settings["static_path"]

    handlers = list(handlers or [])

    static_url_prefix = settings.get("static_url_prefix",

    "/static/")

    static_handler_class = settings.get("static_handler_class",

    StaticFileHandler)

    static_handler_args = settings.get("static_handler_args", {})

    static_handler_args['path'] = path

    for pattern in [re.escape(static_url_prefix) + r"(.*)",

    r"/(favicon\.ico)", r"/(robots\.txt)"]:

    handlers.insert(0, (pattern, static_handler_class,

    static_handler_args))

    if self.settings.get('debug'):

    self.settings.setdefault('autoreload', True)

    self.settings.setdefault('compiled_template_cache', False)

    self.settings.setdefault('static_hash_cache', False)

    self.settings.setdefault('serve_traceback', True)

    self.wildcard_router = _ApplicationRouter(self, handlers)

    self.default_router = _ApplicationRouter(self, [

    Rule(AnyMatches(), self.wildcard_router)

    ])

    # Automatically reload modified modules

    if self.settings.get('autoreload'):

    from tornado import autoreload

    autoreload.start()

    很容易的看到,Application继承的父类都变了。

    新版本的父类ReversibleRouter正是新的tornado.routing模块里面定义的。

    我们的项目代码如下:

    class Application(object):

    def __init__(self):

    from tornado.options import options

    self._options = options

    self._settings = settings

    self._beforecallback = None

    self._shutdown_callback = []

    self._app = None

    def call_shutdown_callback(self):

    for callback in self._shutdown_callback:

    callback()

    def init_settings(self):

    from config import FILE_UPLOAD_PATH

    import tornado.options

    tornado.options.parse_command_line()

    self._settings['static_path'] = FILE_UPLOAD_PATH

    self._settings['static_url_prefix'] = '/upload/'

    self._settings["debug"] = self._options.debug

    self._settings['module'] = self._options.module

    if not self._settings['module']:

    print("the module parameter is required.")

    exit(0)

    else:

    context['module'] = self._settings['module']

    if self._settings["debug"]:

    self._settings["autoreload"] = True

    self.install_autoreload_hook()

    if not self._options.debug:

    args = sys.argv

    args.append("--log_file_prefix=%s" % settings['logfile'])

    tornado.options.parse_command_line(args)

    @property

    def options(self):

    return self._options

    @property

    def handlers(self):

    from urls import handlers

    return handlers

    @property

    def settings(self):

    return self._settings

    def get_app(self):

    self._beforecallback(self)

    self.init_settings()

    self.install_event_hooks()

    self.install_middleware()

    self.install_rbac()

    self.install_message_backend()

    from tornado.web import Application

    return Application(self.handlers, **self._settings)

    本来计划对着新的代码修改下我们的代码, 适配新的版本,不过发现变化比较大。比如这个Route里面的URLSpec也从tornado.web移动到tornado.routing里面了,代码整体变动太大,所以还是去修改服务器的tornado版本吧!

    class Route(object):

    urls = []

    def __call__(self, url, name=None):

    def _(cls):

    if url.startswith("/"):

    _url = r"%s" % url

    else:

    _url = r"/api/%s/%s" % (API_VERSION, url)

    self.urls.append(tornado.web.URLSpec(_url, cls, name=name))

    return cls

    return _

    结论:

    虽然问题不是代码层面解决的,但是也是感慨万千。还有就是感觉运气有点爆棚,上周在服务器一pip install tornado装的4.4, 隔了一周在服务器二pip install tornado就装到4.5了,而且关键变化还挺大,真是坑啊!

    相关文章

      网友评论

          本文标题:一次tornado升级导致的bug,排查了好久,比较坑

          本文链接:https://www.haomeiwen.com/subject/jogfsxtx.html