一次tornado升級(jí)導(dǎo)致的bug聂喇,排查了好久,比較坑

之前一直穩(wěn)定運(yùn)行的代碼蔚携,我引進(jìn)新項(xiàng)目的時(shí)候希太,忽然報(bào)錯(cuò)

'Application' object has no attribute 'handlers'"

困擾許久。而且是時(shí)而正常浮梢,時(shí)而出錯(cuò)跛十。

無(wú)法忍受秕硝,后開(kāi)啟debug模式排查,發(fā)現(xiàn)原來(lái)是tornado4.5起升級(jí)了,引入了新的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代碼已經(jīng)變成:

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繼承的父類(lèi)都變了。

新版本的父類(lèi)ReversibleRouter正是新的tornado.routing模塊里面定義的躯护。

我們的項(xiàng)目代碼如下:

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)

本來(lái)計(jì)劃對(duì)著新的代碼修改下我們的代碼惊来, 適配新的版本,不過(guò)發(fā)現(xiàn)變化比較大棺滞。比如這個(gè)Route里面的URLSpec也從tornado.web移動(dòng)到tornado.routing里面了裁蚁,代碼整體變動(dòng)太大,所以還是去修改服務(wù)器的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 _

結(jié)論:

雖然問(wèn)題不是代碼層面解決的枉证,但是也是感慨萬(wàn)千。還有就是感覺(jué)運(yùn)氣有點(diǎn)爆棚移必,上周在服務(wù)器一pip install tornado裝的4.4室谚, 隔了一周在服務(wù)器二pip install tornado就裝到4.5了,而且關(guān)鍵變化還挺大崔泵,真是坑懊氤唷!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末憎瘸,一起剝皮案震驚了整個(gè)濱河市入篮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌幌甘,老刑警劉巖潮售,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異含潘,居然都是意外死亡饲做,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)遏弱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)盆均,“玉大人,你說(shuō)我怎么就攤上這事漱逸±嵋蹋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵饰抒,是天一觀的道長(zhǎng)肮砾。 經(jīng)常有香客問(wèn)我,道長(zhǎng)袋坑,這世上最難降的妖魔是什么仗处? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上婆誓,老公的妹妹穿的比我還像新娘吃环。我一直安慰自己,他們只是感情好洋幻,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布郁轻。 她就那樣靜靜地躺著,像睡著了一般文留。 火紅的嫁衣襯著肌膚如雪好唯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,713評(píng)論 1 312
  • 那天燥翅,我揣著相機(jī)與錄音骑篙,去河邊找鬼。 笑死权旷,一個(gè)胖子當(dāng)著我的面吹牛替蛉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拄氯,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼躲查,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了译柏?” 一聲冷哼從身側(cè)響起镣煮,我...
    開(kāi)封第一講書(shū)人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鄙麦,沒(méi)想到半個(gè)月后典唇,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胯府,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年介衔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骂因。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡炎咖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寒波,到底是詐尸還是另有隱情乘盼,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布俄烁,位于F島的核電站绸栅,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏页屠。R本人自食惡果不足惜粹胯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一蓖柔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧矛双,春花似錦渊抽、人聲如沸蟆豫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)十减。三九已至栈幸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帮辟,已是汗流浹背速址。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留由驹,地道東北人芍锚。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蔓榄,于是被迫代替她去往敵國(guó)和親并炮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容